生命的意义在于折腾

vue3学习

  1. 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   }
  2. 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:更先进的组件
  3. setup 函数(只能同步,不能异步)

    1. setup执行时机

      • beforeCreate: 表示组件刚刚被创建出来, 组件的data和methods还没有初始化好
      • setup
      • Created : 表示组件刚刚被创建出来, 并且组件的data和methods已经初始化好
    2. setup注意点

      • 由于在执行setup函数的时候, 还没有执行Created生命周期方法 所以在setup函数中,是无法使用data和methods
      • 由于我们不能在setup函数中使用data和methods, 所以Vue为了避免我们错误的使用, 它直接将setup函数中this修改成了undefined
      • setup函数只能是同步的不能是异步的
  4. 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
  5. 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>  
  6. 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>
  7. 递归监听和非递归监听(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
  8. 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>
  9. 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>
  10. 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>
  1. 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
  1. 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
  1. 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>
  1. 响应数据本质

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
  1. 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}
  1. 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的重写使其更快

留言板