一、Vue 程序的基本结构:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
基本结构 | let vm=new Vue({ data:{ // 数据区 }, methods:{ // 方法区 }, }) vm.$mount(‘#app’); | let app=Vue.createApp({ data(){ return { // 数据区 } }, methods:{ // 方法区 } …… }) let vm=app.mount(‘#app’); |
Vue 选项 | 在创建 Vue 类实例的同时,用 Vue 构造函数的参数设置选项。 | 使用 Vue 类的 createApp()方法的参数设置选项。 |
术语 | vm:Vue 实例 | app:Vue 应用实例 vm:根组件实例 |
根组件实例的$data 属性 | vm.$data 可以访问数据区。 vm 也可以访问数据区。 | vm.$data 可以访问数据区。 vm 也可以访问数据区。 /注意:app 不能访问数据区/ |
根组件实例的$el 属性 | vm.$el 指向挂载点元素节点。 | vm.
e
l
不指向挂载点元素节点。
<
b
r
>
(
1
)若挂载点有且仅有一个根节点,则
v
m
.
el 不指向挂载点元素节点。 (1)若挂载点有且仅有一个根节点,则 vm. el不指向挂载点元素节点。<br>(1)若挂载点有且仅有一个根节点,则vm.el 指向该根节点。 (2) 若挂载点有多个根节点,则 vm.$el 指向空的文本节点。 |
数据区 | 数据区是一个对象 | 数据区是一个函数返回的对象。 |
挂载点 | 有两种绑定挂载点的方法: (1) 在 Vue 构造函数中使用 el 选项。 (2) 调用 Vue 实例的$mount()方法。 | 调用 Vue 应用实例的 mount()方法绑定挂载点。 |
二、 组件生命周期的钩子函数:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
创建阶段 | beforeCreate | beforeCreate |
创建阶段 | created | created |
挂载阶段 | beforeMount | beforeMount |
挂载阶段 | mounted | mounted |
更新阶段 | beforeUpdate | beforeUpdate |
更新阶段 | updated | updated |
销毁阶段 | beforeDestroy | beforeUnmount |
销毁阶段 | destroyed | unmounted |
销毁方法 | vm.$destroy() | app.unmount() |
1、 Vue.js 2.x 框架的生命周期流程图:
一、 Vue.js 框架的内置指令:
Vue.js 框架的内置指令在两个版本之间区别不大,内置指令如下表所示。
指令分类 | 具备取值的 Vue 指令 | 不具备取值的 Vue 指令 |
---|---|---|
文本插值 | v-text、t-html | v-once、v-pre |
HTML 属性绑定 | v-bind | - |
事件绑定 | v-on | - |
表单元素数据绑定 | v-model | - |
条件渲染 | v-if、v-else-if、v-show | v-else |
循环渲染 | v-for | - |
遮盖视图闪烁 | - | v-cloak |
Vue.js 3.x 新增指令 | v-slot |
二、 指令的动态参数:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
指令的动态参数 | (无) | v-指令名:[动态参数名] HTML: 数据区:data(){ return { eventName:‘click’ } } |
三、v-on 指令的修饰符:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
用回车键别名做修饰符 | ||
用回车键的 ASCII 码做修饰符 | 该方法被废弃 | |
系统修饰符 | (无) | 新增四个系统修饰符:.ctrl、.alt、.shift、.meta |
鼠标按钮修饰符 | (无) | 新增三个鼠标按钮修饰符:.left、.middle、.right |
一、 组件的注册:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
注册局部组件 | 在 Vue 构造函数的参数中使用 components 选项注册局部组件。 let vm=new Vue({ el:‘#app’, data: {}, method:{}, components:{ 局部组件名:{}, …… } }) | 在 Vue 对象的 createApp()方法的参数中使用 components 选项注册局部组件。 let app=Vue.createApp({ data(){ return {} }, methods:{}, components:{ 组件名:{}, …… } }) app.mount(‘#app’); |
注册全局组件 | 使用 Vue 对象的 component()方法注册全局组件。 Vue.component(‘组件名’,{}); | 使用 Vue 应用实例 app 的 component()方法注册全局组件。 app.component(‘组件名’,{}); 注意:全局组件的注册必须书写在定义 app 和利用 app 的 mount()方法设置挂载点之间的代码区域。 |
二、 组件模板的根节点:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
组件模板的根节点 | 在组件的 template 选项中有且仅有一个根节点。 Vue.component(‘custom-com’,{ template: , }) | 在组件的 template 选项中允许有多个根节点。 app.component(‘custom-com’,{ template: , }) |
三、组件的自定义事件:
组件的自定义事件用于子组件向父组件传递数据,在子组件中使用 this.
e
m
i
t
(
)
对父组件的自定义事件进行手动触发,并将传递给父组件的数据以参数的形式书写在
t
h
i
s
.
emit() 对父组件的自定义事件进行手动触发,并将传递给父组件的数据以参数的形式书写在 this.
emit()对父组件的自定义事件进行手动触发,并将传递给父组件的数据以参数的形式书写在this.emit() 方法中。
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
定义自定义事件 | (无) | 建议在创建组件时,使用 emits 选项定义自定义事件。 template:``, props:[‘title’], emits:[‘custom’] }) |
验证抛出的事件 | (无) | 创建组件时,emits 选项的取值可以是对自定义事件的验证函数。 app.component(‘custom-com’,{ template: , data(){ return { phone:‘’, email:‘’ } }, props:[‘title’], emits:{ custom({phone,email}){ if(phone!“” & & email!“”){ return true; // 表示事件有效 }else{ throw new Error(‘手机号码和电子邮箱不得为空’); return false; // 表示事件无效,并抛出错误 } } }, methods:{ submit(){ this.$emit(‘custom’, {phont:this.phone,email:this.email}); } } }) |
四、 在组件上使用 v-model 指令:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
在组件上使用v-model 指令 | ➢ 父组件中 v-model 指令绑定的数据,子组件中要使用 value 变量进行接收。 ➢ 子组件的 input 事件要触发父组件的 input 事件进行数据回传。 < my-input v-model=“nick”>< /my-input> Vue.component(‘my-input’,{ template: , props:[‘value’], methods:{ txtInput(event){ this.$emit(‘input’,event.target.value) } } }) let vm=new Vue({ data:{ nick:‘’ } }) vm. $mount(‘#app’) | ➢ 父组件中 v-model 指令绑定的数据,子组件中要使用 modelValue 变量进行接收。 ➢ 子组件的 input 事件要触发父组件的 update:modelValue 事件进行数据回传。 < my-input v-model=“nick”> my-input> let app=Vue.createApp({ data(){ return { nick:‘’ } } }); app.component(‘my-input’,{ template: , props:[‘modelValue’], emits:[‘update:modelValue’], methods:{ txtInput(event){ this.$emit(‘update:modelValue’ ,event.target.value); } } }) app.mount(‘#app’) |
在组件上使用多个 v-model 指令 | (无) | 允许在组件中有多个表单元素,此时可以在父组件中使用多个 v-model 指令进行双向绑定。 < my-info v-model:user-nick=“nick” v-model:user-email=“email”> my-info> app.component(‘my-info’,{ props:[‘userNick’,‘userEmail’], emits:[‘update:userNick’,‘update:userEmail’], template: }) app.mount(‘#app’) |
五、 兄弟组件之间的通信:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
中央事件总线技术 | let bus=new Vue(); 发送数据:bus.$emit() 接收数据:bus. $on() | 发送数据:发送方传递给父组件接收数据:父组件传递给接收方 |
父链技术 | 子组件访问父组件:this. p a r e n t 父组件访问子组件: t h i s . parent 父组件访问子组件:this. parent父组件访问子组件:this.children | 子组件访问父组件:this. p a r e n t 子组件访问挂载点: t h i s . parent 子组件访问挂载点:this. parent子组件访问挂载点:this.root 父组件访问子组件:废弃了 this.$children |
子组件索引 | 子组件使用 ref 属性为自身设置索引。 父组件使用 this.$refs.索引名 访问子组件 | 子组件使用 ref 属性为自身设置索引。 父组件使用 this.$refs.索引名 访问子组件 |
六、 组件分发技术:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
匿名插槽 | ➢ 在 my-slot 组件设置匿名插槽: < slot> slot> ➢ 父组件使用插槽:< my-slot>向插槽中插入的内容 my-slot> | ➢ 在 my-slot 组件设置匿名插槽: < slot> slot> ➢ 父组件使用插槽: < my-slot>向插槽中插入的内容 my-slot> |
具名插槽 | ➢ 在 my-slot 组件设置匿名作用域插槽:< slot x=“100” y=“200”> slot> ➢ 父组件使用插槽: < my-slot slot-scope=“sc”> < p>{{sc.x}}< /p> < p>{{sc.y}}< /p> < /my-slot> | ➢ 在 my-slot 组件设置匿名作用域插槽: < slot x=“100” y=“200”>< /slot> ➢ 父组件使用插槽:< my-slot v-slot=“sc”> < p>{{sc.x}}< /p> < p>{{sc.y}}< /p> < /my-slot> |
匿名作用域插槽 | ➢ 在 my-slot 组件设置具名作用域插槽: < slot name=“slotA” x=“100” y=“200”>< /slot> < slot name=“slotB” x=“300” y=“400”>< /slot> ➢ 父组件使用插槽: < my-slot> < template slot=“slotA” slot-scope=“sc”> {{sc.x}} – {{sc.y}} < /template> < template slot=“slotB” slot-scope=“sc”> {{sc.x}} – {{sc.y}} < /template> < /my-slot> | ➢ 在 my-slot 组件设置具名作用域插槽:< slot name=“slotA” x=“100” y=“200”>< /slot> < slot name=“slotB” x=“300” y=“400”>< /slot> ➢ 父组件使用插槽: < my-slot> < template v-slot:slotA=“sc”> {{sc.x}} – {{sc.y}}< /template> < template v-slot:slotB=“sc”> {{sc.x}} – {{sc.y}} < /template> < /my-slot> |
解构作用域插槽 | (无) | < my-slot v-slot:slotA=“{x,y}”> {{x}} – {{y}} < /my-slot> |
七、 组件的非 Prop 属性:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
非 Prop 属性 | (无) | 在创建组件过程中: (1) 使用 props 选项接收的属性是 Prop 属性。 (2) 允许不使用 props 选项接收父组件传递过来的属性,这样的属性是非 Prop 属性。 A) 非 Prop 属性也是单向数据流传递。 B) 非 Prop 属性在子组件中可以使用 this. a t t r s . 非 P r o p 属性名来进行访问。 < b r > C ) 在使用组件时绑定的事件也可以被认定为非 P r o p 属性。 < b r > D ) 自定义事件可以使用 t h i s . attrs.非 Prop 属性名 来进行访问。 C) 在使用组件时绑定的事件也可以被认定为非 Prop 属性。 D) 自定义事件可以使用 this. attrs.非Prop属性名来进行访问。<br>C)在使用组件时绑定的事件也可以被认定为非Prop属性。<br>D)自定义事件可以使用this.attrs.on 自定义事件名() 触发。 例如: 在子组件中触发该事件可以书写为:this.$attrs.onCustom(); |
八、 组件事件的继承:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
组件事件的继承 | (无) | Vue.js 3.x 规定:父组件的事件可以直接继承给同样具备该事件的子组件及其后代组件。 < div id=“app”> < /div> let app=Vue.createApp({ methods:{ boxInput(){ window.alert(event.target.value); } } }) app.component(‘select-specialty’,{ template: < select v-model="specialty"> , data(){ return { specialty:‘前端工程师’ } } }) app.mount(‘#app’) |
禁止组件事件的继承 | (无) | 创建组件时使用下列选项: inheritAttrs: false |
多根节点组件的事件继承 | (无) | 若组件具备多个根节点,同时父组件绑定了事件,根据默认情况下父组件的事件会继承给子组件的这一特性,Vue 框架会报出一个警告。 警告的解决方案为下列两种方法之一: ➢ 禁止父组件向子组件继承事件:即在子组件中书写 inheritAttrs:false 选项。 ➢ 在子组件中需要继承父组件事件的根节点上显式绑定$attrs,这被称为“隐式贯穿”行为。这样可以指定哪个根节点继承父组件的事件 < div id=“app”> < /div> let app=Vue.createApp({ methods:{ divClick(){ window.alert(event.target.textContent); } } })app.component(‘root-test’,{ // inheritAttrs: false, template:` div class=“first”>第一个根节点< div/>
第二个根节点
第三个根节点< div/> })
app.mount(‘#app’) |
九、 多级父子组件的通信:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
多级父子组件的通信技术 | (无) | 使用 Provide/Inject 技术完成多级父子组件的通信: ➢ 父组件使用 provide 选项向外发送数据。 ➢ 子组件使用 inject 选项接收父组件发送的数据。 < div id=“app”> < com-parent> < com-child>< /com-child> < /com-parent> < /div> let app=Vue.createApp({ data(){ return { studentName:‘张三’, studentInfo:{sex:‘男’,age:25} } }, provide(){ // 发送数据 return { sName:this.studentName, sInfo:this.studentInfo } } }) app.component(‘com-parent’,{ template:` < div class=“parent”> < slot>< /slot> < /div> }) app.component(‘com-child’,{ template: |
Provide 数据的响应性 | (无) | 默认情况下,通过 Provide/Inject 技术从父组件传递给子组件的数据并不是响应式的。 解决方案: ➢父组件 Provide 的数据需要分配一个组合式 API 的 computed 属性。 ➢子组件在访问 Inject 注入的数据时必须使用 value 属性。 父组件提供数据: provide(){ return { sName:Vue.computed(()=>this.studentName), sInfo:Vue.computed(()=>this.studentInfo) } } 子组件接收数据: inject:[‘sName’,‘sInfo’], methods:{ btnClick(){ console.log(this.sName.value); console.log(this.sInfo.value.sex,this.sInfo.value.age); } } |
一、createElement 函数的引入:
1、创建组件时,允许使用 render()函数替代 template 生成组件的 DOM 结构。
2、render()函数最终返回的是虚拟 DOM 节点。
3、虚拟 DOM 节点使用 createElement()函数创建。
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
createElement函数的引入 | createElement 函数是 render()函数的参数。 Vue.component(‘my-com’,{ render(createElement){ retrun createElement(‘div’); } }) createElement 函数也可以简写为 h 函数。 Vue.component(‘my-com’,{ render(h){ retrun h(‘div’); } }) | 废弃了 createElement 函数,直接使用 h 函数。 h 函数是从 Vue 对象中解构出来的。 let {h}=Vue; app.component(‘my-com’,{ render(){ return h(‘div’); } }) |
二、虚拟 DOM 节点的节点特性:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
虚拟 DOM 节点的节点特性 | 节点特性分门别类称,整合为对象,成为 h 函数的第二个参数。 h(‘div’,{ attrs:{id: ‘box’}, props:{boxRadius: ‘50%’}, style:{ width: ‘200px’; height: ‘150px’; }, class:{ ok:true, bgc:true }, on:{ mouseover:function(){ this.divOver(); } } }, ‘一个块级元素’) | 节点特性扁平化书写,整合为对象,成为 h 函数的第二个参数。 h(‘div’,{ id:‘box’, boxRadius: ‘50%’, style:[{width:‘200px’},{height:‘150px’}], class:[‘ok’,{bgc:true}], onMouseover:()=>{ this.divOver(); } }, ‘一个块级元素’) |
class 属性的设置方式 | 为虚拟 DOM 节点设置单个类名: 方法一:h(‘div’,{ class:{box:true} },‘虚拟 DOM 节点’) 方法二:createElement(‘div’,{ attrs:{class:‘box’} },‘虚拟 DOM 节点’) 为虚拟 DOM 节点设置多个类名: 方法一:createElement(‘div’,{ class:{box:true,item:true} },‘虚拟 DOM 节点’) 方法二: reateElement(‘div’,{ attrs:{class:‘box item’} },‘虚拟 DOM 节点’) | 为虚拟 DOM 节点设置单个类名: 方法一:h(‘div’,{class:‘box’},‘虚拟 DOM 节点’) 方法二:h(‘div’,{class:{box:true},‘虚拟 DOM 节点’) 为虚拟 DOM 节点设置多个类名: 方法一:h(‘div’,{ class:{box:true,item:true} },‘虚拟 DOM 节点’) 方法二:h(‘div’,{ class:[{box:true,item:true}] },‘虚拟 DOM 节点’) 方法三:h(‘div’,{ class:[‘box’,{item:true} },‘虚拟 DOM 节点’) |
三、创建带有插槽的虚拟 DOM 节点:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
带有匿名插槽的虚拟 DOM 节点 | h(div,{ class:{box:true} },this.$slots.default) | h(div,{ class:{box:true} },this.$slots.default()) |
带有具名插槽的虚拟 DOM 节点 | h(div,{ class:{box:true} },this.$slots.default) | h(div,{ class:{box:true} },this.$slots.default()) |
带有具名插槽的虚拟 DOM 节点 | h(div,{ class:{box:true} },[ h(‘h1’,this.$slots.abc), h (‘em’,this. $slots.xyz) ]) | h(‘div’,{ class:{box:true} },[ h(‘h1’,this.$slots.abc()), h (‘em’,this. $slots.xyz()) ]) |
带有匿名作用域插槽的虚拟 DOM 节点 | h(‘div’,this.$scopedSlots.default({ a:100, b:200 })) | h(‘div’,this.$slots.default({ a:100, b:200 })) |
带有具名作用域插槽的虚拟 DOM 节点 | h(‘div’,[ h(‘h1’,this.$ scopedSlots.abc({ a:100, b:200 })), h(‘h2’,this.$scopedSlots.xyz({ x: ‘A’, y: ‘B’ })) ]) | h(‘div’,[ h(‘h1’,this.$ slots.abc({ a:100, b:200 })), h(‘h2’,this.$slots.xyz({ x: ‘A’, y: ‘B’ })) ]) |
四、函数化组件:
Vue.js 2.x | Vue.js 3.x | |
---|---|---|
函数化组件 | Vue.component(‘my-fun’,{ functional:true, render(h,context){ return h(‘p’,context.props.title); }, props:[‘title’] }) | let {h}=Vue; let app=Vue.createApp({}) app.component(‘myFun’, props,context)=>{ return h(‘p’,props.title) }); app.mount(‘#app’) |