苏州网站建设行业,做暧暧的网站,电子商务公司logo,百度一下你就知道手机版官网0、vue2和vue3对比
框架版本API方式双向绑定原理domFragmentsTree-Shakingvue2选项式API#xff08;Options API#xff09;基于Object.defineProperty#xff08;监听#xff09;实现#xff0c;不能双向绑定对象类型的数据【通过Object.defineProperty里面的set和get做…0、vue2和vue3对比
框架版本API方式双向绑定原理domFragmentsTree-Shakingvue2选项式APIOptions API基于Object.defineProperty监听实现不能双向绑定对象类型的数据【通过Object.defineProperty里面的set和get做对象劫持在处理数组等对象类型数据时则是重写原型方法push、pop等方法可以被监听】每次更新diff都是全量对比template标签里面只能有一个根节点div标签import语法引用组件import xxx from xxxvue3组合式APIComposition API基于Proxy劫持实现能够双向绑定对象类型的数据只对比有标记的对标记部分进行更新大大减少静态内容的对比消耗动态内容是{{}}双向绑定的内容template标签里面支持多个根节点div标签实现原理通过虚拟节点实现import语法引用组件时将全局API分块不使用的功能不会出现在基础包中减少打包体积import {aaa} from xxx
0.1 vue3新特性
重写双向数据绑定VDOM性能瓶颈Fragments增加了Suspense teleport和多v-model用法Tree-Shaking的支持在保持代码运行结果不变的情况下去除无用的代码组合式APIComposition APIsetup语法糖
0.2 vue3的三种书写风格
Options APIsetupsetup 语法糖
// 第一种书写风格Options API
template
/templatescript
export default{data() {return{// 数据}},methods: {}
}
/scriptstyle
/style// 第二种书写风格setup
templatediv{{a}}/div
/templatescript
setup() {const a 1// 变量需要手动return才能在dom中使用return{a}
}
/scriptstyle
/style// 第三种书写风格setup语法糖后lang选择使用是js语言
templatediv{{a}}/div
/templatescript setup langts
const a:number 1
/scriptstyle
/style1、vue语法
vue语法
插值语法{{}}指令语法v-
1.1 插值语法
templatedivp{{data}}/p/div
/templatescript setup langts
const data {name: 张三,age: 30,like: 吃饭
}
/scriptstyle scoped
/style
1.2 vue指令
v-开头的都是vue内置指令 v-text 用来显示文本 v-html 用来展示富文本支持标签如spanxxx/span不支持组件如组件名xxx/组件名 v-if 用来控制元素的显示隐藏切换真假DOMfalse时注释掉dom节点 v-else-if 表示 v-if 的v-else-if 可以链式调用 v-else v-if条件收尾语句 v-show 用来控制元素的显示隐藏false时将节点设置不可见display:none block Css切换性能比v-if高 v-on 简写 用来给元素添加/绑定事件v-on:click语法糖简写click v-bind 简写:用来绑定元素的属性Attrv-bind:id语法糖简写:id v-model 双向绑定 v-for 用来遍历元素 v-on 修饰符 冒泡案例 v-once 性能优化只渲染一次 v-memo 性能优化会有缓存
1.2.1 点击事件动态事件类型切换
// 动态事件切换
template// 静态事件button clickclickBtn按钮点击/button// 动态事件动态事件切换button [event]clickBtn按钮点击/button/templatescript
// const event click // [event]等于click
const event doubleClick // [event]等于doubleClick
const clickBtn (){console.log(点击按钮了……)
}
/script1.2.2 点击事件阻止点击冒泡
点击冒泡当父级节点和子级节点都有点击事件时点击子级节点也会触发父级节点的点击事件
// 动态事件切换
templatediv clickparentClickbutton [event].stopclickBtn按钮点击/button/div
/templatescript
const parentClick (){console.log(点击了父级)
}
// const event click // [event]等于click
const event doubleClick // [event]等于doubleClick
const clickBtn (){console.log(点击按钮了……)
}
/script属性作用[event].stop阻止点击冒泡触发父级节点的点击事件但是对单击事件有效对双击事件无效[event].prevent阻止提交表单[event].once只触发一次后面再点击多少次都不会触发[event].capture[event].middle[event].left[event].right[event].passive[event].self
1.2.3 v-bind 绑定元素属性
绑定id、class、style……
templatediv :ididp :stylestyle段落段落段落/pbutton :class[a, b] click.middleclickBtn()子1按钮/buttonbutton :class[a] [event].passiveclickBtn()子2按钮/button/div
/templatescript setup
// 事件
const event click // [event]等于click
const clickBtn (){console.log(点击按钮了……)
}// 属性
const id myid
const style {color: green,border: 1px solid green
}
/scriptstyle scoped
#myid{background-color: #ccc;
}
.a{background-color: blue;
}
.b{color: red;
}
/style1.2.4 v-model 绑定表单元素ref响应式双向绑定
响应式的数据双向绑定通过ref和reactive v-model can only be used on input, textarea and select elements.
templatedivinput v-modeldata typetext/p{{data}}/p/div
/templatescript setup
import {ref} from vue// 双向绑定通过ref和reactive
const data ref(测试内容)
/scriptstyle scoped
/style1.2.5 v-once 单次渲染【基本数据类型】待完善
v-once仅渲染元素和组件一次并跳过之后的更新 在随后的重新渲染元素/组件及其所有子项将被当作静态内容并跳过染。这可以用来优化更新时的性能。
templatediv!-- 基本数据类型 --input v-modelmsg typetext/!-- 对照组 --p对照组 {{msg}}/phr /!-- v-once 实验组 --!-- 单个元素 --p v-onceThis will never change:{{msg}}/p!-- 带有子元素的元素 --div v-onceh1comment/h1p{{msg}}/p/div!-- 待完善 --!-- 组件 --!-- A v-once :commentmsg / --!-- v-for指令 --ulli v-fori in list v-once{{i}}/li/ul/div
/templatescript setup langts
import {ref} from vue
// import A from A.vue // 报错
// import B from B.vueconst msg ref(测试内容)
const list:string[] [春, 夏, 秋, 东]
/scriptstyle scoped
/style1.2.6 v-memo 单次渲染【数组】待完善
templatediv!-- v-memo 处理对象数据类型 --!-- v-for指令 --p v-for(item, index) in list对照组 {{index}}--{{item}}/phr /p v-for(item, index) in list v-memoindex 2v-memo组 {{index}}--{{item}}/p!-- 组件 --!-- A v-once :commentmsg / --/div
/templatescript setup langts
import {ref, computed} from vue
// import A from A.vue
// import B from B.vueconst msg ref(测试内容)
let list ref([春, 夏, 秋, 冬])// 模拟异步更新
// 定时刷新数据函数-----------还没有写出来报错
const timer ref(0)
const index ref(0)
let count 1
let list computed({get() {},set(newVal) {console.log(count: , count)list [赵, 钱, 孙, 李]console.log(list)}
})
// setTimeout(changeData, 3000)
// setTimeout(changeData, 3000)
// setTimeout(changeData, 3000)
// setInterval(changeData, 3000)/scriptstyle scoped
/style
1.2.7 v-for 遍历
templatedivinput v-for(item, index) in data typetext valueitem/p :keyindex v-for(item, index) in data{{index}}--{{item}}/p/div
/templatescript setup langts
import {ref} from vueconst data:string[] [春, 夏, 秋, 东]
/scriptstyle scoped
/style从生成的dom结构来看使用v-for的标签效果是循环生成多个完整标签内容标签样式数据而不仅仅是生成“一个完整标签多条数据”
2、虚拟dom和diff算法
虚拟DOM就是通过JS来生成一个AST节点树抽象语法树
vue3的diff算法分为三类
无key三步 有key五步前序尾序乱序最长递增子序列
3、Ref 全家桶
ref深层次响应式shallowRef浅层次响应式isRef判断是否是ref对象返回值true或falsetriggerRef强制视图更新customRef自定义ref
3.1 响应式ref 、shallowRef、triggerRef 或 reactive
1非响应式修改data之后页面数据不更新
templatedivp{{data}}/pbutton clickclickBtn()修改/button/div
/templatescript setup langts
let data {name: 张三}
const clickBtn (){data.name 李四console.log(data)
}
/script2响应式利用ref双向绑定修改data之后页面数据也更新
templatedivp{{data}}/pbutton clickclickBtn()修改/button/div
/templatescript setup langts
import {ref} from vue
let data ref({name: 张三}) // 使用ref
const clickBtn (){data.value.name 李四 // 通过value更新console.log(data)
}
/script编辑器报错但能用不知道HBuilderX为什么报错B站老师的vscode就没有报错 3响应式shallowRef
templatedivp{{data1}}/pp{{data2}}/pbutton clickclickBtn1()修改Ref/buttonbutton clickclickBtn2()修改shallowRef/button/div
/templatescript setup langts
import {ref} from vuelet data1 ref({name: 张三})
let data2 ref({name: 张三三})
const clickBtn1 (){data1.value.name 李四 // value.name console.log(data1)
}
const clickBtn2 (){data2.value {name: 李四四} // value console.log(data2)
}
/script3.2 ref、shallowRef、triggerRef
ref、shallowRef 不能同时使用在一个事件中shallowRef 会被影响即使写成xxx.value.namexxx也会被改变造成页面视图的更新 triggerRef 强制更新shallowRef 会被影响由于 ref 底层调用了 triggerRef所以 ref、shallowRef 同时使用时 shallowRef 会被影响
3.3 customRef自定义ref
templatedivpcustomRef: {{obj}}/pbutton clickclickBtn()修改/button/div
/templatescript setup langts
import {customRef} from vuefunction MyRef(value){let timer nullreturn customRef((track,trigger){return{get(){track()return value},set(newValue){// 不防抖每次点击clickBtn都会触发然而实际上只更新一次因为clickBtn中修改每次都是同一个值并不是变化的// console.log(触发了)// value newValue// trigger()// 防抖clearTimeout(timer)timer setTimeout((){console.log(触发了)value newValuetimer nulltrigger()}, 3000)}}})
}const obj MyRef(王五)const clickBtn (){obj.value 修改了console.log(obj)
}
/script3.5 reactive【绑定表单场景中使用较多】
ref、reactive 区别
ref 支持所有数据类型reactive 支持引用类型数据Array、Object、Map、Setref 取值、赋值都需要加上.valuereactive 不用
基础版例子
templatedivpreactive: {{form}}/pbutton clickclickBtn()修改/button/div
/templatescript setup langts
import {reactive} from vuetype M {name: string,age: number
}
let form reactiveM({name: 张三,age: 30
})const clickBtn (){form.name 李四form.age 31console.log(form)
}
/scriptreactive 绑定数组响应式更新视图
templatedivulli v-foritem in list{{item}}/li/ulbutton clickclickBtn()添加/button/div
/templatescript setup langts
import {reactive} from vue// let list [] // 非响应式不会更新视图
let list reactive([]) // 响应式动态更新视图
// let list reactivestring []([]) // 添加泛型字符串数组类型const clickBtn (){list.push(item)console.log(list)
}
/script异步请求场景模拟不破坏响应式的数据更新方式示例。解决方案数组push解构
templatedivulli v-foritem in list{{item}}/li/ulbutton clickclickBtn()添加/button/div
/templatescript setup langts
import {reactive} from vue// let list [] // 非响应式不会更新视图
let list reactive([]) // 响应式动态更新视图
// let list reactivestring []([]) // 添加泛型字符串数组类型// 模拟异步请求更新数据
const clickBtn (){setTimeout((){const res [one, two, three] // 模拟后端返回数据// list res // 这样赋值list数据能更新但是页面视图不会更新// 因为reactive是Proxy代理的对象直接赋值会覆盖代理对象破坏响应式方案// 解决方案list.push(...res) // 数组解构console.log(list)}, 300)
}
/script解决方案二对象数组作为对象的一个属性直接修改对象的数组属性
templatedivulli v-foritem in list.arr{{item}}/li/ulbutton clickclickBtn()添加/button/div
/templatescript setup langts
import {reactive} from vue// 对象
let list reactive{arr:string[]}({arr: []
}) // 响应式动态更新视图// 模拟异步请求更新数据
const clickBtn (){setTimeout((){const res [one, two, three] // 模拟后端返回数据// list res // 这样赋值list数据能更新但是页面视图不会更新// 因为reactive是Proxy代理的对象直接赋值会覆盖代理对象破坏响应式方案// 解决方案list.arr resconsole.log(list)}, 300)
}
/script3.6 readonly
把 reactive 的值变成只读 但是 readonly 会受原始变量更新的影响
script setup langts
import {reactive} from vuelet obj reactive({name: 张三})
let obj_read readonly(obj)
// 不能修改只读属性的值
obj_read.name 李四 // 编译报错obj_read 是只读属性
// 能修改原始变量的值
obj.name 李四
// 这里打印 obj、obj_read发现都会变成李四readonly 会受原始变量更新的影响
/script3.7 shallowReactive
templatedivp{{obj}}/pbutton clickclickBtn()修改/button/div
/templatescript setup langts
import {reactive, shallowReactive} from vuelet obj:any shallowReactive({foo: { // 外层bar: { // 二层name: 张三 // 三层}}
})
const clickBtn (){console.log(点击了)// 修改外层【正确修改】obj.foo {barChange: 李四}// 【错误修改】// 修改二层// obj.foo.bar {// nameChange: 赵六 // 非响应式// }// obj.foo.bar.value {// nameChange: 赵六 // 追加元素// }// 修改最内层三层// obj.foo.bar.name 李四 // 非响应式页面视图不更新// 修改obj// obj { // 非响应式页面视图不更新// fooChange: 王五// }// obj.value { // 响应式相当于追加一个元素value:{fooChange: 王五}// fooChange: 王五// }// console.log(obj)
}
/scriptstyle scoped
/style
修改外层【正确修改】 修改二层、三层都是非响应式
修改obj
3.8 shallowRef、shallowReactive
相同shallowReactive 也是浅层次响应式与 shallowRef 会被 ref 影响相同shallowReactive 也会被 reactive 影响 区别 shallowRef 实现响应式需要通过.value修改数据shallowReactive 不需要
// shallowRef
let data ref({name: 张三})
const clickBtn1 (){data.value.name 李四 // 方式一 value.name data.value {name: 李四四} // 方式二 value console.log(data)
}// shallowReactive
let obj:any shallowReactive({foo: { // 外层bar: { // 二层name: 张三 // 三层}}
})
const clickBtn1 (){obj.foo {barChange: 李四}
}4、to 全家桶
toRef将普通数据转成ref对象响应式然后响应式修改对象的值转成ref对象修改值需要加.value。只能修改响应式对象的值。非响应式对象的data会改变但是视图不会改变。接收参数toRef(对象名, 对象属性)toRefs批量将数据转成ref对象响应式然后响应式修改对象的值toRaw与toRef相反将ref对象转成普通对象/普通类型数据脱离Proxy代理Proxy实现双向绑定/响应式脱离Proxy即非响应式。只想修改数据、不想更新视图的时候可以用toRaw
// toRef 实现响应式修改数据的值
// 转成ref对象
const like toRef(person, like) // 接收参数toRef(对象名, 对象属性)
// 响应式修改
like.value 运动 // like是一个ref对象所以修改值需要加.value// toRefs
const person reactive({name: 张三,age: 30,like: 吃饭
})
// 接收参数对象名返回值对象内的所有属性名
const {name, age, like} toRefs(person) // 解构取值
// 响应式修改
name.value 李四
age.value 31
like.value 运动完整例子 toRef 的例子
templatedivp{{person}}/pbutton clickclickBtn()修改/button/div
/templatescript setup langts
import {reactive, toRef} from vueconst person reactive({ // 实现对象类型数据的响应式可以直接使用reactivereactive实现对象类型数据的响应式ref实现所有类型数据的响应式name: 张三,age: 30,like: 吃饭
})
const clickBtn (){const like toRef(person, like) // 接收参数toRef(对象名, 对象属性)like.value 运动 // like是一个ref对象所以修改值需要加.valueconsole.log(like:,like)console.log(person:,person)
}
/scripttoRefs 的例子
templatedivp{{person}}/pbutton clickclickBtn()修改/button/div
/templatescript setup langts
import {reactive, toRef, toRefs} from vueconst person reactive({name: 张三,age: 30,like: 吃饭
})
// toRefs实现原理批量转成ref对象
// const toRefs T extends object(object:T){
// const map:any {}
// for(let key in object){
// map[key] toRef(object, key) // 将对象object中的属性key转成ref对象
// }
// return map // 将object内所有属性转成ref并返回
// }const clickBtn (){const {name, age, like} toRefs(person) // 接收参数对象名返回值对象内的所有属性名name.value 李四age.value 31like.value 运动console.log(person:,person)
}
/scriptstyle scoped
/style 【补充】ts泛型
script setup langts
import {ref} from vue
import type {Ref} from vue // 添加泛型方式2type Data {name: string
}
let data1 refData({name: 张三}) // 添加泛型方式1
let data2:RefData ref({name: 张三}) // 添加泛型方式2当类型比较复杂的时候推荐使用
/script