当前位置: 首页 > news >正文

Vue2-重要知识点

数据监视

vm是Vue的实例对象

数据代理:data中的数据都做了数据代理来自vm._data,可以直接写vm.a代替vm._data,是因为Vue有数据代理

数据劫持:简单点就是被代理对应有set和get方法

Vue监测对象中的数据,对后添加的属性加响应式

Vue.set(target,propertyName,value) 或 vm.$set(target,propertyName,value)

例1:this.$set(this.student,‘name’,‘张三’)(响应式)

例2:list = [{age:18}]给List第一个元素对象添加属性 this.list[0].name = ‘张三’ (无响应式)

Vue监测数组中的数据

  1. 用这七个API:push(),pop(),shift(),unshift(),splice(),sort(),reverse()
  2. Vue.set(target,index,value) 或 vm.$set(target,index,value)

例:this.arrName.splice(0,1,‘张三’) 或者 this.$set(this.arrName,0,‘张三’)

特别注意:Vue.set() 和 vm.set() 不能对vm 或vm的数据对象(data 和 _data)添加属性!!!

Vc和Vm关系

简单创建vm(Vue的实例对象)和vc(组件的实例对象)

<div id="root"><school/>
</div>
<script>//组件的实例对象就是vc(VueComponent)const school = Vue.extend({name:'school',})//Vue的实例对象就是vmconst vm = new Vue({el:'root',// 注册school组件(局部注册)components:{school,}})
</script>

vm和vc的关系

在这里插入图片描述

ref 属性

<template><div><h1 ref="title">欢迎学习Vue</h1><School ref="sch"/></div>
</template><script>import School from './components/School'export default {name:'App',components:{ School },data() {return {}},methods: {showDOM(){console.log(this.$refs.title) // 真实DOM元素console.log(this.$refs.sch)   // School组件的实例对象(vc)}},}
</script>

props 配置项

<template><div><Student name="李四" sex="" :age="18"/></div>
</template><script>import Student from './components/Student'export default {name:'App',components:{ Student }}
</script>
<template><div><h2>学生姓名:{{ name }}</h2><h2>学生性别:{{ sex }}</h2><h2>学生年龄:{{ myAge }}</h2><button @click="updateAge">尝试修改收到的年龄</button></div>
</template><script>
export default {name: "Student",data() {return {myAge: this.age,};},methods: {updateAge() {this.myAge++; // 不能直接改变age,通过myAge间接改变}, },// 第一种:简单声明接收// props:['name','age','sex']// 第二种:接收的同时对数据进行类型限制//   props: {//     name: String,//     age: Number,//     sex: String,//   }// 第三种:接收的同时对数据:进行类型限制+默认值的指定+必要性的限制props: {name: {type: String,  //字符串类型required: true, //name是必要的},age: {type: Number,default: 99, //默认值},sex: {type: String,required: true,},},
};
</script>

注意:

  1. props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中,然后去修改data中的数据
  2. 也可以传递方法,通过方法名传递(跟变量名一样)。

mixin 混入

将一些通用的变量、方法、初始化方法等封装起来

定义混入(mixin.js)

export const hunhe = {methods: {showName(){alert(this.name)}},mounted(){console.log('你好啊!')}
}
export const hunhe2 = {data(){return{x: 100,y: 200}}
}

使用混入

<template><div><h1 @click="showName">学生姓名:{{name}}</h1><h1>x:{{x}}</h1><h1>y:{{y}}</h1></div>
</template><script>
import {hunhe,hunhe2} from '../mixin'
export default {name:'Student',data() {return {name: "张三"}},mixins:[hunhe,hunhe2]
}
</script>

全局使用(不建议使用)

import Vue from 'vue'
import App from './App.vue'
import {hunhe,hunhe2} from "@/mixin";Vue.config.productionTip = false
Vue.mixin(hunhe)
Vue.mixin(hunhe2)
new Vue({render: h => h(App),
}).$mount('#app')

注意:

  1. 混入中的变量、方法和组件中的重复会优先使用组件中的(不使用混入中的)
  2. 混入中mounted()这种生命周期钩子和组件中重复,双放都生效,先加载混入中的

plugin 插件

install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据

定义插件(plugins.js)

export default {install(Vue,x,y,z){console.log(x,y,z)//全局过滤器Vue.filter('mySlice', function(value){return value.slice(0,4)})//定义混入Vue.mixin({data() {return {x:100,y:200}},})//给Vue原型上添加一个方法(vm和vc就都能用了)Vue.prototype.hello = ()=>{alert('你好啊')}}
}

使用插件

import Vue from 'vue'
import App from './App.vue'
import plugins from './plugins'	// 引入插件Vue.config.productionTip = falseVue.use(plugins,1,2,3)	// 应用(使用)插件new Vue({el:'#app',render: h => h(App)
})
<template><div><h2>{{ name | mySlice }}</h2><h2>{{ x }}</h2><h2>{{ y }}</h2><button @click="test">点我测试一个hello方法</button></div>
</template><script>
export default {name:'School',data() {return {name:'111111111111111111111',}},methods: {test(){this.hello()}},
}
</script>

scoped样式

  1. 作用:让样式在局部生效,防止多个组件用定义相同样式名冲突
  2. 写法:

游览器本地存储

存储内容大小一般支持 5MB 左右(不同浏览器可能还不一样)

浏览器端通过Window.sessionStorage 或者 Window.localStorage属性来实现本地存储机制

  1. SessionStorage存储的内容会随着浏览器窗口关闭而消失
  2. LocalStorage存储的内容,需要手动清除才会消失

相关API:

  1. xxxStorage.setItem(‘key’, ‘value’)把键值对添加到存储中,如果键名存在,则更新其对应的值
  2. xxxStorage.getItem(‘key’)
  3. xxxStorage.removeItem(‘key’)该键名从存储中删除
  4. xxxStorage.clear()该方法会清空存储中的所有数据

localStorage

<button onclick="saveDate()">点我保存数据</button><br/>
<button onclick="readDate()">点我读数据</button><br/>
<button onclick="deleteDate()">点我删除数据</button><br/>
<button onclick="deleteAllDate()">点我清空数据</button><br/>
<script>let person = {name:"JOJO",age:20}function saveDate(){localStorage.setItem('msg','localStorage')localStorage.setItem('person',JSON.stringify(person))}function readDate(){console.log(localStorage.getItem('msg'))const person = localStorage.getItem('person')console.log(JSON.parse(person))}function deleteDate(){localStorage.removeItem('msg')localStorage.removeItem('person')}function deleteAllDate(){localStorage.clear()}
</script>

sessionStorage

<button onclick="saveDate()">点我保存数据</button><br/>
<button onclick="readDate()">点我读数据</button><br/>
<button onclick="deleteDate()">点我删除数据</button><br/>
<button onclick="deleteAllDate()">点我清空数据</button><br/>
<script>let person = {name:"JOJO",age:20}function saveDate(){sessionStorage.setItem('msg','sessionStorage')sessionStorage.setItem('person',JSON.stringify(person))}function readDate(){console.log(sessionStorage.getItem('msg'))const person = sessionStorage.getItem('person')console.log(JSON.parse(person))}function deleteDate(){sessionStorage.removeItem('msg')sessionStorage.removeItem('person')}function deleteAllDate(){sessionStorage.clear()}
</script>

组件的自定义事件

子给父转数据

props方式:

  1. 一种组件间通信的方式,适用于:父组件 ===> 子组件 (父给子传数据)

自定义事件:

  1. 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第一种写法,使用@或v-on)
    1. 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第二种写法,使用ref)

全局事件总线:

App.vue

<template><div class="app"><!-- props方式: --> <!-- 通过父组件给子组件传递函数类型的props实现子给父传递数据 --><School :mps="getSchoolName"/><!-- 自定义事件: --> <!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第一种写法,使用@或v-on) --><Student @mps="getStudentName"/><!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第二种写法,使用ref) --><Student ref="student"/></div>
</template><script>
import Student from './components/Student'
import School from './components/School'export default {name:'App',components:{School,Student},methods: {getSchoolName(name){console.log('App收到了学校名:',name)},getStudentName(name){console.log('App收到了学生名:',name)},},mounted() {this.$refs.student.$on('mps',this.getStudentName) // 绑定自定义事件// this.$refs.student.$once('mps',this.getStudentName) // 绑定自定义事件(一次性)},
}
</script>

School.vue

<template><div><h2>学校名称:{{ name }}</h2><button @click="schoolName111">给App传schoolName</button></div>
</template><script>
export default {name: 'School',data() {return {name: "石家庄信息工程",};},props:['mps'],methods: {schoolName111(){this.mps(this.name)}},
};
</script>

Student.vue

<template><div class="demo"><h2>学生名称:{{ name }}</h2><button @click="studentName111">给App传studentName</button><button @click="unbind">解绑atguigu事件</button><button @click="death">销毁当前Student组件的实例(vc)</button></div>
</template><script>
export default {name:'Student',data() {return {name:'马朋帅',}},methods: {studentName111(){// 触发Student组件实例身上的atguigu事件this.$emit('mps',this.name)},unbind(){// 解绑this.$off('mps') //解绑一个自定义事件// this.$off(['mps','demo']) //解绑多个自定义事件// this.$off() //解绑所有的自定义事件},death(){// 销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效this.$destroy()}},
}
</script>

注意:直接在里面写回调函数要用箭头函数(this会指向这条代码所在的vc)

//结合上面的代码


this.$refs.student.$on('mps',(name)=>{console.log(name)console.log(this) //App的vc对象
}) this.$refs.student.$on('mps',function (name){console.log(name)console.log(this) //Student的vc对象
})

全局事件总线

一种可以在任意组件间通信的方式

main.js

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = falsenew Vue({render: h => h(App),beforeCreate() {Vue.prototype.$bus = this // 安装全局事件总线}}).$mount('#app')

App.vue

<template><div class="app"><School/><Student/></div>
</template><script>
import Student from './components/Student'
import School from './components/School'export default {name:'App',components:{ School, Student }
}
</script>

School.vue

<template><div></div>
</template><script>
export default {name: "School",mounted() {this.$bus.$on("mps", (data) => {console.log("我是School组件,收到了数据", data);});},beforeDestroy() {this.$bus.$off("mps");},
};
</script>

Student.vue

<template><div><h2>学生姓名:{{ name }}</h2><button @click="sendStudentName">把学生名给School组件</button></div>
</template><script>
export default {name:'Student',data() {return {name:'马朋帅',}},methods: {sendStudentName(){this.$bus.$emit('mps', this.name)}}
}
</script>

消息的订阅与发布

一种组件间通信的方式,适用于任意组件间通信。

使用步骤:

  1. 安装pubsub:npm i pubsub-js
  2. 引入: import pubsub from ‘pubsub-js’
  3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
methods:{demo(data){......}
}
......
mounted() {this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}
  1. 提供数据:pubsub.publish(‘xxx’,数据)
  2. 最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

示例代码

  1. 订阅消息(School.vue)
<script>import pubsub from 'pubsub-js'export default {name:'School',data() {return {name:'尚硅谷',address:'北京',}},mounted() {this.pubId = pubsub.subscribe('hello',(msgName,data)=>{console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)})},beforeDestroy() {pubsub.unsubscribe(this.pubId)},}
</script>
  1. 发布消息(Student.vue)
<script>import pubsub from 'pubsub-js'export default {name:'Student',data() {return {name:'张三',sex:'男',}},methods: {sendStudentName(){pubsub.publish('hello',666)}},}
</script>

$nextTick

  1. 语法:this.$nextTick(回调函数)
  2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
  3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

具体案例

this.$nextTick(function(){this.$refs.inputTitle.focus()
}

过度与动画

作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。

写法:

  • 元素进入的样式:

    v-enter:进入的起点

    v-enter-active:进入过程中

    v-enter-to:进入的终点

  • 元素离开的样式:

    v-leave:离开的起点

    v-leave-active:离开过程中

    v-leave-to:离开的终点

  • 使用<transition>包裹要过渡的元素,并配置name属性:

  • 若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。

  • appear属性的作用:刷页面时,执行需要执行的动画

具体案例(单个元素过渡)

<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition appear><h1 v-show="isShow">你好啊!</h1></transition></div>
</template><script>export default {name:'Test',data() {return {isShow:true}},}
</script><style scoped>h1{background-color: orange;}.v-enter-active{animation: move 0.5s linear;}.v-leave-active{animation: move 0.5s linear reverse;}@keyframes move {from{transform: translateX(-100%);}to{transform: translateX(0px);}}
</style>

name 的作用可以让让不同的元素有不同的动画效果


<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition name="hello" appear><h1 v-show="isShow">你好啊!</h1></transition></div>
</template><script>export default {name:'Test',data() {return {isShow:true}},}
</script><style scoped>h1{background-color: orange;}.hello-enter-active{animation: move 0.5s linear;}.hello-leave-active{animation: move 0.5s linear reverse;}@keyframes move {from{transform: translateX(-100%);}to{transform: translateX(0px);}}
</style>

具体案例(多个元素过渡)

<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition-group name="hello" appear><h1 v-show="!isShow" key="1">你好啊!</h1><h1 v-show="isShow" key="2">哈哈哈!</h1></transition-group></div>
</template><script>export default {name:'Test',data() {return {isShow:true}},}
</script><style scoped>h1{background-color: orange;}/* 进入的起点、离开的终点 */.hello-enter,.hello-leave-to{transform: translateX(-100%);}.hello-enter-active,.hello-leave-active{transition: 0.5s linear;}/* 进入的终点、离开的起点 */.hello-enter-to,.hello-leave{transform: translateX(0);}
</style>

使用第三库的具体案例,库的名称:Animate.css
安装:npm i animate.css
引入:import ‘animate.css’

<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition-groupappearname="animate__animated animate__bounce"enter-active-class="animate__swing"leave-active-class="animate__backOutUp"><h1 v-show="!isShow" key="1">你好啊!</h1><h1 v-show="isShow" key="2">哈哈哈!</h1></transition-group></div>
</template><script>
import 'animate.css'
export default {name:'Test',data() {return {isShow:true}},
}
</script><style scoped>
h1{background-color: orange;
}
</style>

插槽

1.作用

  1. 让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件

2.分类

  1. 默认插槽
  2. 具名插槽
  3. 作用域插槽
    1. 普通的作用域插槽
    2. 解构插槽

3.使用方式

1.默认插槽:

父组件中:<Category><div>html结构1</div></Category>
子组件中:<template><div><!-- 定义插槽 --><slot>插槽默认内容...</slot></div></template>

注意:

  • 当父组件没有给插槽传数据时则显示里面的内容。
  • 如果子组件的 template 中没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

2.具名插槽:

父组件中:<Category><template v-slot:center><div>html结构1</div></template><!--没有包含在带有v-slot的<template>中的内容都会被视为默认插槽的内容或者<template>上加v-slot:default。--><!--<template v-slot:default><div>html结构2</div></template>--><template><div>html结构2</div></template><template v-slot:footer><div>html结构3</div></template><!-- 注意:v-slot:footer 和 #footer 是两种不同的写法,效果都一样。--><!--<template #footer><a href="">更多</a></template>--></Category>
子组件中:<template><div><!-- 定义插槽 --><slot name="center">center插槽默认内容...</slot><slot>默认插槽默认内容...</slot><slot name="footer">footer插槽默认内容...</slot></div></template>

3.作用域插槽:

  1. 理解:数据在组件的自身(子组件),但根据数据生成的结构需要组件的使用者(父组件)来决定。(games数据在Category(子)组件中,但使用数据所遍历出来的结构由App(父)组件决定)

  2. 具体编码:

    父组件中:<Category><!-- scopeData可以是自定义的任何名称 --><template v-slot:default="scopeData"><ul><li v-for="g in scopeData.games" :key="g">{{g}}</li></ul></template></Category><Category><!-- scopeData获取子组件的信息,在内容中使用 --><template v-slot="scopeData"><h4 v-for="g in scopeData.games" :key="g">{{g}}</h4></template></Category>
    子组件中:<template><div><!-- 通过数据绑定就可以把子组件的数据传到父组件 --><slot :games="games"></slot></div></template><script>export default {name:'Category',//数据在子组件自身data() {return {games:['红色警戒','穿越火线','劲舞团','超级玛丽']}},}</script>
    

    注意:v-slot始终放在组件里面的标签上,特殊情况可以直接放在组件标签上但是懒的记,总之放在上不会错。

4.解构插槽

  1. 理解:使用解构插槽可以直接使用传递过来的对象,跟上面的插槽相比就是去掉了scopeData,直接使用games。

  2. 具体代码:

    1. 未使用解构插槽的方式

      子组件current-user中:<template><div><slot :user="user">默认内容</slot></div></template><script>export default {data() {return {user: {firstName: 'du',lastName: 'li'}}}}</script>
      父组件中:<current-user><template v-slot:default="slotProps">{{ slotProps.user.firstName }}</template></current-user>
      
    2. 使用解构插槽的方式

      父组件中:<current-user><!-- 解构插槽 --><!-- 名称必须跟子组件的保持一致都用user --><template v-slot="{ user }">{{ user.firstName }}</template></current-user>
      
    3. 给user重命名为person

      父组件中:<current-user><template v-slot="{ user: person }">{{ person.firstName }}</template></current-user>
      
    4. 给user设置默认值

      父组件中:<current-user><template v-slot="{ user = { firstName: 'duli' } }">{{ user.firstName }}</template></current-user>
      

4.简写方式

  1. v-slot:替换为字符 #。如 v-slot:center 缩写为 #center

    <Category><template #center><div>html结构1</div></template><template ><div>html结构2</div></template><template #footer><div>html结构3</div></template>
    </Category>
    
  2. 解构插槽没用名称时缩写注意点

    <!-- 这样会报错 -->
    <current-user><template #="{ user }">{{ user.firstName }}</template>
    </current-user>
    <!-- 正确写法 -->
    <current-user><template #default="{ user }">{{ user.firstName }}</template>
    </current-user>
    

相关文章:

  • Linux学习——UDP
  • 中间系统-基础
  • 移远通信智能模组助力东成“无边界智能割草机器人“闪耀欧美市场
  • 护眼-科学使用显示器
  • 在离线 Ubuntu 环境下部署双 Neo4j 实例(Prod Dev)
  • 使用Arduino板读取CHT832X温湿度
  • Linux 网络编程:select、poll 与 epoll 深度解析 —— 从基础到高并发实战
  • 探索科技的边界:代理IP与汽车产业链的创新之旅
  • 2023蓝帽杯初赛内存取证-2
  • el-table中el-input的autofocus无法自动聚焦的解决方案
  • Cursor这类编程Agent软件的模型架构与工作流程
  • 深入探讨:如何完美完成标签分类任务(数据治理中分类分级的分类思考)
  • 成熟软件项目解决方案:360°全景影像显控软件系统
  • [Godot] C#2D平台游戏基础移动和进阶跳跃代码
  • 【git】subtree拆分大的git库到多个独立git库
  • 施磊老师基于muduo网络库的集群聊天服务器(四)
  • Unitest和pytest使用方法
  • Web网页核心技术解析:从结构到节点操作
  • 如何将当前文件夹及其子文件夹下的所有word提取到一个excel里
  • 常用第三方库:dio网络库使用与封装
  • 印尼塔劳群岛发生6.2级地震,震源深度140千米
  • 黎巴嫩“伊斯兰集团”组织证实其高级成员在以军空袭中丧生
  • 委托第三方可一次性补缴十多万元的多年社保?广州多人涉嫌被骗后报警
  • 中纪委驻中组部纪检监察组原组长李刚被捕
  • 国家新闻出版署:4月共118款国产网络游戏获批
  • “解压方程式”主题沙龙:用艺术、精油与自然的力量,寻找自我疗愈的方式