一、vue基础用法
mvvm的了解/认知
- 语义化模板
- mvc - model view controller
- mvvm - model view view-model
vue是如何利用mvvm思想进行开发
双向数据绑定
- 花括号,构建了数据与视图的双向绑定
- 通过视图绑定事件,来处理数据
生命周期-vue示例
- 建立:beforeCreate=>created=>beforeMount=>mounted
- 更新:beforeUpdate=>updated
- 销毁:beforeDestory=>destoryed
生命周期-过程
- bC:new Vue() - 实例挂载功能
- c:data、props、methods、computed - 数据操作,不涉及vdom和dom
- bM:vDom - 围绕vDom做的数据操作,但是不涉及dom
- m:dom-任何操作
- bU:bDom更新了的,但是dom还没更新-可以更新数据
- u:dom已经更新了,但是谨慎操作数据
- bD:实例vm尚未被销毁-eventBus、store、计时器销毁
- d:实力完全被销毁-收尾
定向监听 (watch和computed)
相同点
- 基于vue的依赖收集机制
- 都是被依赖的数据发生变化触发,进而进行改变
、处理计算
不同点
- 入和出
computed:多入单出-多个值变化,组成一个值的变化
watch:单入多出-单个值的变化,进而影响一系列的变更。(这里的多出指的是,在声明的watch变量中,可以针对某一个变量的变化,改变其他变量的值) - 性能上
computed:会自动diff依赖,如果依赖没有变化,则直接从缓存中读取值
watch:无论监听值是否变化,只能通过回调获取值 - 写法上
computed:必须有return
watch:可有可无,有的话也不影响 - 时机上
computed:从首次生成就赋值,开始运行了
watch:首次默认不执行,可以通过immediate:true
条件v-if & v-show & v-else & v-else-if
- v-if无dom,不会渲染实际节点和其子节点
- v-show存在实际节点和其子节点,但不展示、不占位
v-for+key
v-for & v-if 循环的优先级
在vue2.x中,v-if和v-for同时使用,v-for优先级更高
在vue3中,v-if始终高于v-for
key的作用
- 模板编译原理 - template => dom
template=>匹配语法 — 生成AST(虚拟树) : 静态 + 动态 => 转换AST为可执行方法 => render() => dom - key作用
dom diff - 单层复用、双向指针、优先服用
key => 快速识别节点的可复用
默认指令
v-once - 只渲染一次
v-text - 只渲染字符串
v-html -渲染html,慎用,防止攻击脚本的注入
v-model - 双向绑定 => :value + @input
二、vue进阶
特征一:模板化
插槽:组件外部维护参数以及结构,内部安排位置
- 面试点 => 默认插槽实现的方式 => 整个插槽的聚合(将所有的节点整合在一起,插入到对应默认插槽的位置)
- 问题 => 多个插槽节点分开布局 => 具名插槽
具名插槽 - 通过name标识插槽身份,从而在组件内部区分
- 面试点 => 所有插槽都是通过name索引,默认插槽其实通过”default“索引。name索引的其实是一段解析上下文的空间
- 参数的传递、参数的隔离
- 问题 => 插槽参数自管理 => 作用域插槽
作用域插槽
外部做结构描述勾勒,内部做传参
- 结构化的传递(jsx)
//具名插槽
let slotNode_header = (<div>vue header</div>)
//作用域插槽
let scope_slot_content = slotProps => {return (<div>{slotProps}</div>)}render() {return (// slotNode_headerscope_slot_content())
}
App.vue
<template><div><HelloWorld>//默认插槽<p>{{msg1}}</p><p>{{msg2}}</p><p>{{msg3}}</p>//具名插槽<template v-slot:header>{{headerMsg}}</template>//作用域插槽<template slot="content" slot-scope="{slotProps}">{{slotProps}}</template>//作用域插槽新版本写法<template v-slot:slotProps="slotProps">{{slotProps}}</template></HelloWorld/></div>
<template>
HelloWorld.vue
<template><div>//默认插槽<slot></slot>//具名插槽<slot name="header"></slot>//作用域插槽<slot name="content" :slotProps="slotProps"></slot></div>
<template>
模板的二次加工
- watch 、computed => 数据与数据之间的加工
- 复杂的模板相关数据计算
- 方案一:函数(methods) | 过滤器(filters) => 过滤器拿不到实例
- 方法二:v-html - 逻辑运算 + 结构拼装 => 安全性
- 方案三:jsx优点和劣势 => template=>render=>vm.render() diff key 直接绕过template使用render渲染,但是强更新,如果稍微有变量等变化的话,会重新更新render函数
语法糖实现
options : [{value:1},{value:2}]
render(h){const Node = (<p>{this.num>100?100:this.num}</p>)const handleChange = ()=>{}// return Nodereturn (<ul>{//v-forthis.options.map(item=>{return (//嵌入// <itemNode></itemNode>//v-model<itemNode item={item} value={item.value} onInput={this.handleChange}><Node/> </itemNode>)})}</ul>)
}
特征二:组件化
Vue.component('component',{template:'<h1>xxx</h1>'
})
new Vue({el:'#app'
})
- 抽象复用
- 精简
混入mixin - 逻辑混入
- 应用:抽离公共逻辑(逻辑相同,模板不同,可复用mixin)
- 合并策略:
- 变量补充不会被覆盖
- 生命周期在引用该mixin组件之前
- 同样被引入的两个mixin,根据引用顺序安排加载顺序
继承拓展extends-逻辑上的共同扩展
- 应用:核心逻辑的功能继承
- 合并策略:
- 变量补充,不会覆盖
- 无论是业务代码还是mixin都在extends之后
extend.js
export default{data(){return {msg:'xxx'}},created(){console.log('extend') }
}
helloword.vue
export default{mixins:['mixin1'],extends:['extend']data(){return {msg:'xxx'}},created(){console.log('extend') }
}
执行顺序:extends > mixin > 引入组件
整体拓展类 - extend
从预定的配置中拓展出来一个独立的配置项进行合并
main.js
xxxxxx
new Vue({el:'#app',component:{App},template:'<App/>'
})
//构造一个扩展器
let _baseOptions = {data:function(){return {course:'xx',session:'vue'}}
}
const BaseComponent = Vue.extend(_baseOptions)
new BaseComponent({created(){console.log('extend componets')}
})
以上方法基于vue2的写法,vue3写法如下,不再使用mixin,extends等拓展
addon.js
import {reactive} from 'vue'
export default function addon(){const title = 'xxx'const obj = reactive({name:'xxx',value:'xxx'})return {title,obj}
}
引入方
<script setup>
import addon from 'addon.js'
const {title:title1,obj:obj1} = addon
</script>