vue3学习
-
Vue3.0是如何变快的?
- diff算法优化: https://vue-next-template-explorer.netlify.app/
- Vue2中的虚拟dom是进行全量的对比
- Vue3新增了静态标记(PatchFlag), 在与上次虚拟节点进行对比时候,只对比带有patch flag的节点 并且可以通过flag的信息得知当前节点要对比的具体内容
- hoistStatic 静态提升
- Vue2中无论元素是否参与更新, 每次都会重新创建, 然后再渲染
- Vue3中对于不参与更新的元素, 会做静态提升, 只会被创建一次, 在渲染时直接复用即可
- cacheHandlers 事件侦听器缓存
- 默认情况下onClick会被视为动态绑定, 所以每次都会去追踪它的变化 但是因为是同一个函数,所以没有追踪变化, 直接缓存起来复用即可
- ssr渲染
- 当有大量静态的内容时候,这些内容会被当做纯字符串推进一个buffer里面, 即使存在动态的绑定,会通过模板插值嵌入进去。这样会比通过虚拟dmo来渲染的快上很多很多。
- 当静态内容大到一定量级时候,会用_createStaticVNode方法在客户端去生成一个static node, 这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。
javascript
1 // 附录: PatchFlags 2 export const enum PatchFlags { 3 TEXT = 1,// 动态文本节点 4 CLASS = 1 << 1, // 2 // 动态 class 5 STYLE = 1 << 2, // 4 // 动态 style 6 PROPS = 1 << 3, // 8 // 动态属性,但不包含类名和样式 7 FULL_PROPS = 1 << 4, // 16 // 具有动态 key 属性,当 key 改变时,需要进行完整的 diff 比较。 8 HYDRATE_EVENTS = 1 << 5, // 32 // 带有监听事件的节点 9 STABLE_FRAGMENT = 1 << 6, // 64 // 一个不会改变子节点顺序的 fragment 10 KEYED_FRAGMENT = 1 << 7, // 128 // 带有 key 属性的 fragment 或部分子字节有 key 11 UNKEYED_FRAGMENT = 1 << 8, // 256 // 子节点没有 key 的 fragment 12 NEED_PATCH = 1 << 9, // 512 // 一个节点只会进行非 props 比较 13 DYNAMIC_SLOTS = 1 << 10, // 1024 // 动态 slot 14 HOISTED = -1, // 静态节点 15 // 指示在 diff 过程应该要退出优化模式 16 BAIL = -2 17 }
- diff算法优化: https://vue-next-template-explorer.netlify.app/
-
Vue3.0六大亮点
- Performance:性能比Vue 2.x快1.2~2倍
- Tree shaking support:按需编译,体积比Vue2.x更小
- Composition API: 组合API(类似React Hooks)
- Better TypeScript support:更好的 Ts 支持
- Custom Renderer API:暴露了自定义渲染API
- Fragment, Teleport(Protal), Suspense:更先进的组件
-
setup 函数(只能同步,不能异步)
-
setup执行时机
- beforeCreate: 表示组件刚刚被创建出来, 组件的data和methods还没有初始化好
- setup
- Created : 表示组件刚刚被创建出来, 并且组件的data和methods已经初始化好
-
setup注意点
- 由于在执行setup函数的时候, 还没有执行Created生命周期方法 所以在setup函数中,是无法使用data和methods
- 由于我们不能在setup函数中使用data和methods, 所以Vue为了避免我们错误的使用, 它直接将setup函数中this修改成了undefined
- setup函数只能是同步的不能是异步的
-
-
reactive
javascript
1 <template> 2 <div> 3 <p>{{state.time}}</p> 4 <button @click="myFn">按钮</button> 5 </div> 6 </template> 7 8 <script> 9 /* 10 1.什么是reactive? 11 - reactive是Vue3中提供的实现响应式数据的方法 12 - 在Vue2中响应式数据是通过defineProperty来实现的 13 而在Vue3中响应式数据是通过ES6的Proxy来实现的 14 2.reactive注意点: 15 - reactive参数必须是对象(json/arr) 16 - 如果给reactive传递了其它对象 17 + 默认情况下修改对象, 界面不会自动更新 18 + 如果想更新, 可以通过重新赋值的方式 19 * */ 20 import {reactive} from 'vue'; 21 export default { 22 name: 'App', 23 setup() { 24 // 创建一个响应式数据 25 // 本质: 就是将传入的数据包装成一个Proxy对象 26 // let state = reactive(123); 27 // let state = reactive({ 28 // age: 123 29 // }); 30 // let state = reactive([1, 3, 5]); 31 let state = reactive({ 32 time: new Date() 33 }); 34 function myFn() { 35 // state = 666; // 由于在创建响应式数据的时候传递的不是一个对象, 所以无法实现响应式 36 // state.age = 666; 37 // state[0] = 666; 38 // 直接修改以前的, 界面不会更新 39 // state.time.setDate(state.time.getDate() + 1); 40 // 重新赋值 41 const newTime = new Date(state.time.getTime()); 42 newTime.setDate(state.time.getDate() + 1); 43 state.time = newTime; 44 console.log(state.time); 45 } 46 return {state, myFn}; 47 } 48 } 49 </script> 50
-
ref
javascript
1 <template> 2 <div> 3 <!-- <p>{{state.age}}</p>--> 4 <!-- 5 注意点: 6 如果是通过ref创建的数据, 那么在template中使用的时候不用通过.value来获取 7 因为Vue会自动给我们添加.value 8 --> 9 <p>{{age}}</p> 10 <button @click="myFn">按钮</button> 11 </div> 12 </template> 13 14 <script> 15 /* 16 1.什么是ref? 17 - ref和reactive一样, 也是用来实现响应式数据的方法 18 - 由于reactive必须传递一个对象, 所以导致在企业开发中 19 如果我们只想让某个变量实现响应式的时候会非常麻烦 20 所以Vue3就给我们提供了ref方法, 实现对简单值的监听 21 2.ref本质: 22 - ref底层的本质其实还是reactive 23 系统会自动根据我们给ref传入的值将它转换成 24 ref(xx) -> reactive({value:xx}) 25 3.ref注意点: 26 - 在Vue中使用ref的值不用通过value获取 27 - 在JS中使用ref的值必须通过value获取 28 * */ 29 // import {reactive} from 'vue'; 30 import {ref} from 'vue'; 31 export default { 32 name: 'App', 33 setup() { 34 // let state = reactive({ 35 // age: 18 36 // }) 37 /* 38 ref本质: 39 ref本质其实还是reactive 40 当我们给ref函数传递一个值之后, ref函数底层会自动将ref转换成reactive 41 ref(18) -> reactive({value: 18}) 42 * */ 43 let age = ref(18); 44 function myFn() { 45 // state.age = 666; 46 // age = 666; 47 age.value = 666; 48 console.log(age); 49 } 50 return {age, myFn} 51 } 52 } 53 </script>
-
reactive 和 ref 区别
javascript
1 <template> 2 <div> 3 <!-- 4 ref和reactive区别: 5 如果在template里使用的是ref类型的数据, 那么Vue会自动帮我们添加.value 6 如果在template里使用的是reactive类型的数据, 那么Vue不会自动帮我们添加.value 7 8 Vue是如何决定是否需要自动添加.value的 9 Vue在解析数据之前, 会自动判断这个数据是否是ref类型的, 10 如果是就自动添加.value, 如果不是就不自动添加.value 11 12 Vue是如何判断当前的数据是否是ref类型的 13 通过当前数据的__v_ref来判断的 14 如果有这个私有的属性, 并且取值为true, 那么就代表是一个ref类型的数据 15 --> 16 <p>{{age}}</p> 17 <button @click="myFn">按钮</button> 18 </div> 19 </template> 20 21 <script> 22 /* 23 1.ref和reactive区别 24 - 如果是reactive在template中不会自动添加.value 25 26 2.reactive为什么不会自动添加.value? 27 - 因为Vue在添加的时候首先会判断当前数据类型是ref还是reactive 28 29 3.Vue如何判断? 30 通过包装后的是有属性 31 __v-isRef 32 33 4.我们如何判断数据到底是ref还是reactive? 34 通过isRef / isReactive 方法 35 * */ 36 import {isRef, isReactive} from 'vue'; 37 import {reactive} from 'vue'; 38 // import {ref} from 'vue'; 39 export default { 40 name: 'App', 41 setup() { 42 // ref(18) -> reactive({value: 18}) 43 // let age = ref(18); 44 let age = reactive({value: 18}); 45 function myFn() { 46 console.log(isRef(age)); 47 console.log(isReactive(age)); 48 age.value = 666; 49 } 50 return {age, myFn} 51 } 52 } 53 </script>
-
递归监听和非递归监听(shallowReactive,shallowRef)
javascript
1 <template> 2 <div> 3 <p>{{state.a}}</p> 4 <p>{{state.gf.b}}</p> 5 <p>{{state.gf.f.c}}</p> 6 <p>{{state.gf.f.s.d}}</p> 7 <button @click="myFn">按钮</button> 8 </div> 9 </template> 10 11 <script> 12 /* 13 1.递归监听存在的问题 14 如果数据量比较大, 非常消耗性能 15 16 2.非递归监听 17 shallowRef / shallowReactive 18 19 3.如何触发非递归监听属性更新界面? 20 如果是shallowRef类型数据, 可以通过triggerRef来触发 21 22 4.应用场景 23 一般情况下我们使用 ref和reactive即可 24 只有在需要监听的数据量比较大的时候, 我们才使用shallowRef/shallowReactive 25 * */ 26 import {shallowReactive} from 'vue'; 27 import {shallowRef, triggerRef} from 'vue'; 28 export default { 29 name: 'App', 30 setup() { 31 // let state = shallowReactive({ 32 let state = shallowRef({ 33 a:'a', 34 gf:{ 35 b:'b', 36 f:{ 37 c:'c', 38 s:{ 39 d:'d' 40 } 41 } 42 } 43 }); 44 function myFn() { 45 // state.a = '1'; 46 // state.gf.b = '2'; 47 // state.gf.f.c = '3'; 48 // state.gf.f.s.d = '4'; 49 // 50 // console.log(state); 51 // console.log(state.gf); 52 // console.log(state.gf.f); 53 // console.log(state.gf.f.s); 54 55 // state.value = { 56 // a:'1', 57 // gf:{ 58 // b:'2', 59 // f:{ 60 // c:'3', 61 // s:{ 62 // d:'4' 63 // } 64 // } 65 // } 66 // } 67 68 // state.value.a = '1'; 69 // state.value.gf.b = '2'; 70 // state.value.gf.f.c = '3'; 71 // state.value.gf.f.s.d = '4'; 72 73 state.value.gf.f.s.d = '4'; 74 // 注意点: Vue3只提供了triggerRef方法, 没有提供triggerReactive方法 75 // 所以如果是reactive类型的数据, 那么是无法主动触发界面更新的 76 triggerRef(state); 77 78 // 注意点: 如果是通过shallowRef创建数据, 79 // 那么Vue监听的是.value的变化, 并不是第一层的变化 80 console.log(state); 81 console.log(state.value); 82 console.log(state.value.gf); 83 console.log(state.value.gf.f); 84 console.log(state.value.gf.f.s); 85 86 } 87 return {state, myFn} 88 } 89 } 90 </script> 91
-
toRaw 做一些不想被监听的事情(提升性能)
javascript
1 <template> 2 <div> 3 <p>{{state}}</p> 4 <button @click="myFn">按钮</button> 5 </div> 6 </template> 7 8 <script> 9 /* 10 1.toRaw 11 从Reactive 或 Ref中得到原始数据 12 13 2.toRaw作用 14 做一些不想被监听的事情(提升性能) 15 * */ 16 import {reactive, toRaw} from 'vue'; 17 export default { 18 name: 'App', 19 setup() { 20 let obj = {name:'lnj', age:18}; 21 /* 22 ref/reactive数据类型的特点: 23 每次修改都会被追踪, 都会更新UI界面, 但是这样其实是非常消耗性能的 24 所以如果我们有一些操作不需要追踪, 不需要更新UI界面, 那么这个时候, 25 我们就可以通过toRaw方法拿到它的原始数据, 对原始数据进行修改 26 这样就不会被追踪, 这样就不会更新UI界面, 这样性能就好了 27 * */ 28 let state = reactive(obj); 29 let obj2 = toRaw(state); 30 // console.log(obj === obj2); // true 31 32 // console.log(obj === state); // false 33 // state和obj的关系: 34 // 引用关系, state的本质是一个Proxy对象, 在这个Proxy对象中引用了obj 35 36 function myFn() { 37 // 如果直接修改obj, 那么是无法触发界面更新的 38 // 只有通过包装之后的对象来修改, 才会触发界面的更新 39 obj2.name = 'zs'; 40 console.log(obj2); // {name: "zs", age: 18} 41 console.log(state); // {name: "zs", age: 18} 42 // state.name = 'zs'; 43 // console.log(state); 44 } 45 return {state, myFn} 46 } 47 } 48 </script>
-
markRaw 将数据标记为永远不能追踪的数据
javascript
1 <template> 2 <div> 3 <p>{{state}}</p> 4 <button @click="myFn">按钮</button> 5 </div> 6 </template> 7 8 <script> 9 /* 10 1.markRaw 11 将数据标记为永远不能追踪的数据 12 一般在编写自己的第三方库时使用 13 * */ 14 import {reactive, markRaw} from 'vue'; 15 export default { 16 name: 'App', 17 setup() { 18 let obj = {name: 'lnj', age: 18}; 19 obj = markRaw(obj); 20 let state = reactive(obj); 21 function myFn() { 22 state.name = 'zs'; 23 } 24 return {state, myFn} 25 } 26 } 27 </script>
-
toRef 和 toRefs
javascript
1 <template> 2 <div> 3 <p>{{state}}</p> 4 <button @click="myFn">按钮</button> 5 </div> 6</template> 7 8<script> 9 /* 10 1.toRef 11 创建一个ref类型数据, 并和以前的数据关联 12 2.toRefs 13 批量创建ref类型数据, 并和以前数据关联 14 3.toRef和ref区别 15 ref-创建出来的数据和以前无关(复制) 16 toRef-创建出来的数据和以前的有关(引用) 17 ref-数据变化会自动更新界面 18 toRef-数据变化不会自动更新界面 19 * */ 20 import {ref, toRef, toRefs} from 'vue'; 21export default { 22 name: 'App', 23 setup() { 24 let obj = {name:'lnj', age:18}; 25 // let name = toRef(obj, 'name'); 26 // let age = toRef(obj, 'age'); 27 let state = toRefs(obj); 28 29 function myFn() { 30 // name.value = 'zs'; 31 // age.value = 666; 32 state.name.value = 'zs'; 33 state.age.value = 666; 34 console.log(obj); 35 console.log(state); 36 // console.log(name); 37 // console.log(age); 38 } 39 return {state, myFn} 40 } 41} 42</script>
- customRef 返回一个ref对象,可以显式地控制依赖追踪和触发响应
javascript
1<template> 2 <div> 3 <p>{{age}}</p> 4 <button @click="myFn">按钮</button> 5 </div> 6</template> 7 8<script> 9 /* 10 1.customRef 11 返回一个ref对象,可以显式地控制依赖追踪和触发响应 12 * */ 13 import {ref, customRef} from 'vue'; 14 15function myRef(value) { 16 return customRef((track, trigger)=>{ 17 return { 18 get(){ 19 track(); // 告诉Vue这个数据是需要追踪变化的 20 console.log('get', value); 21 return value; 22 }, 23 set(newValue){ 24 console.log('set', newValue); 25 value = newValue; 26 trigger(); // 告诉Vue触发界面更新 27 } 28 } 29 }); 30} 31export default { 32 name: 'App', 33 setup() { 34 // let age = ref(18); // reactive({value: 18}) 35 let age = myRef(18); 36 function myFn() { 37 age.value += 1; 38 } 39 return {age, myFn} 40 } 41} 42</script>
javascript
1<template> 2 <ul> 3 <li v-for="item in state" :key="item.id">{{item.name}}</li> 4 </ul> 5</template> 6 7<script> 8 /* 9 1.customRef 10 返回一个ref对象,可以显式地控制依赖追踪和触发响应 11 * */ 12 import {ref, customRef} from 'vue'; 13 14function myRef(value) { 15 return customRef((track, trigger)=>{ 16 fetch(value) 17 .then((res)=>{ 18 return res.json(); 19 }) 20 .then((data)=>{ 21 console.log(data); 22 value = data; 23 trigger(); 24 }) 25 .catch((err)=>{ 26 console.log(err); 27 }) 28 return { 29 get(){ 30 track(); // 告诉Vue这个数据是需要追踪变化的 31 console.log('get', value) 32 // 注意点: 33 // 不能在get方法中发送网络请求 34 // 渲染界面 -> 调用get -> 发送网络请求 35 // 保存数据 -> 更新界面 -> 调用get 36 return value; 37 }, 38 set(newValue){ 39 console.log('set', newValue); 40 value = newValue; 41 trigger(); // 告诉Vue触发界面更新 42 } 43 } 44 }); 45} 46 47export default { 48 name: 'App', 49 // setup函数: 只能是一个同步的函数, 不能是一个异步的函数 50 setup() { 51 /* 52 let state = ref([]); 53 fetch('../public/data.json') 54 .then((res)=>{ 55 return res.json(); 56 }) 57 .then((data)=>{ 58 console.log(data); 59 state.value = data; 60 }) 61 .catch((err)=>{ 62 console.log(err); 63 }) 64 */ 65 let state = myRef('../public/data.json'); 66 return {state}; 67 } 68} 69</script> 70
- ref 获取dom元素
javascript
1<template> 2 <div ref="box">我是div</div> 3</template> 4 5<script> 6 /* 7 1.获取元素 8 在Vue2.x中我们可以通过给元素添加ref='xxx', 9 然后再代码中通过refs.xxx的方式来获取元素 10 在Vue3.x中我们也可以通过ref来获取元素 11 * */ 12 import {ref, onMounted} from 'vue'; 13export default { 14 name: 'App', 15 /* 16 beforeCreate 17 setup 18 Created 19 * */ 20 setup() { 21 // console.log(this.$refs.box); 22 let box = ref(null); // reactive({value: null}) 23 24 onMounted(()=>{ 25 console.log('onMounted',box.value); 26 }); 27 28 console.log(box.value); // null 29 30 return {box}; 31 } 32} 33</script> 34
- readonly
javascript
1<template> 2 <div> 3 <p>{{state.name}}</p> 4 <p>{{state.attr.age}}</p> 5 <p>{{state.attr.height}}</p> 6 <button @click="myFn">按钮</button> 7 </div> 8</template> 9 10<script> 11 12 /* 13 1.readonly 14 - 只读数据 15 16 2.readonly和const 17 - const 赋值保护 18 - readonly 递归保护 19 20 3.isReadonly 21 - 判断是否是readonly 22 23 4.shallowReadonly 24 - 非递归保护 25 * */ 26 import {readonly, isReadonly, shallowReadonly} from 'vue' 27export default { 28 name: 'App', 29 setup() { 30 // readonly:用于创建一个只读的数据, 并且是递归只读 31 let state = readonly({name:'lnj', attr:{age:18, height: 1.88}}); 32 // shallowReadonly: 用于创建一个只读的数据, 但是不是递归只读的 33 // let state = shallowReadonly({name:'lnj', attr:{age:18, height: 1.88}}); 34 // const和readonly区别: 35 // const: 赋值保护, 不能给变量重新赋值 36 // readonly: 属性保护, 不能给属性重新赋值 37 // const value = 123; 38 const value = {name:'zs', age:123}; 39 function myFn() { 40 state.name = '知播渔'; 41 state.attr.age = 666; 42 state.attr.height = 1.66; 43 console.log(state); 44 console.log(isReadonly(state)); 45 // value = 456; 46 // console.log(value); 47 value.name = 'ls'; 48 value.age = 456; 49 console.log(value); 50 } 51 return {state, myFn}; 52 } 53} 54</script>
- 响应数据本质
javascript
1/* 21.Proxy注意点 3- set方法必须通过返回值告诉Proxy此次操作是否成功 4* */ 5// let obj = {name:'lnj', age:18}; 6let arr = [1, 3, 5]; // [1, 3, 5, 7] 7let state = new Proxy(arr, { 8 get(obj, key){ 9 console.log(obj, key); // [ 1, 3, 5 ] 1 10 return obj[key]; 11 }, 12 set(obj, key, value){ 13 // [ 1, 3, 5 ] 3 7 14 // [ 1, 3, 5, 7 ] length 4 15 console.log(obj, key, value); 16 obj[key] = value; 17 console.log('更新UI界面'); 18 return true; 19 } 20}); 21 22// console.log(state[1]); 23state.push(7); 24
- shallowRef 和 shallowReactive实现原理
javascript
1/* 21.shallowReactive, shallowRef 32.shallowReadonly 43.reactive, ref 54.readonly 6* */ 7 8function shallowRef(val) { 9 return shallowReactive({value:val}); 10} 11 12function shallowReactive(obj) { 13 return new Proxy(obj, { 14 get(obj, key){ 15 return obj[key]; 16 }, 17 set(obj, key, val){ 18 obj[key] = val; 19 console.log('更新UI界面'); 20 return true; 21 } 22 }) 23} 24let obj = { 25 a:'a', 26 gf:{ 27 b:'b', 28 f:{ 29 c:'c', 30 s:{ 31 d:'d' 32 } 33 } 34 } 35}; 36/* 37let state = shallowReactive(obj); 38 39// state.a = '1'; 40state.gf.b = '2'; 41state.gf.f.c = '3'; 42state.gf.f.s.d = '4'; 43 */ 44let state = shallowRef(obj); 45 46// state.value.a = '1'; 47// state.value.gf.b = '2'; 48// state.value.gf.f.c = '3'; 49// state.value.gf.f.s.d = '4'; 50state.value = { 51 a:1, 52 gf:{ 53 b:2, 54 f:{ 55 c:3, 56 s:{ 57 d:4 58 } 59 } 60 } 61}
- ref 和 reactive 原理
javascript
1/* 21.shallowReactive, shallowRef 32.shallowReadonly 43.reactive, ref 54.readonly 6* */ 7 8function shallowRef(val) { 9 return shallowReactive({value:val}); 10} 11 12function shallowReactive(obj) { 13 return new Proxy(obj, { 14 get(obj, key){ 15 return obj[key]; 16 }, 17 set(obj, key, val){ 18 obj[key] = val; 19 console.log('更新UI界面'); 20 return true; 21 } 22 }) 23} 24let obj = { 25 a:'a', 26 gf:{ 27 b:'b', 28 f:{ 29 c:'c', 30 s:{ 31 d:'d' 32 } 33 } 34 } 35}; 36/* 37let state = shallowReactive(obj); 38 39// state.a = '1'; 40state.gf.b = '2'; 41state.gf.f.c = '3'; 42state.gf.f.s.d = '4'; 43 */ 44let state = shallowRef(obj); 45 46// state.value.a = '1'; 47// state.value.gf.b = '2'; 48// state.value.gf.f.c = '3'; 49// state.value.gf.f.s.d = '4'; 50state.value = { 51 a:1, 52 gf:{ 53 b:2, 54 f:{ 55 c:3, 56 s:{ 57 d:4 58 } 59 } 60 } 61} 62 63 64
阅读量:1988发布日期:2021-06-11 17:07:35
博客描述
vue2到vue3速度有一个显著提升,虚拟dom的重写使其更快