zoukankan      html  css  js  c++  java
  • VUE3.0 总结

    Vue3.0的六大亮点:

    • Performance:性能比 Vue2.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:更先进的组件

    Vue3.0变的更快:

    1. diff 方法优化:

      • Vue2.x中的虚拟DOM是进行全量对比
      • Vue3.0新增了静态标记(PatchFlag),虚拟DOM对比时,只对比带有patch flag 的节点
        export function render(_ctx, _cache, $props, $setup, $data, $options) {
          return (_openBlock(), _createBlock("div", null, [
            _createVNode("p", null, "你好,小明"),
            _createVNode("p", null, "你好,小明"),
            _createVNode("p", null, "你好,小明"),
            _createVNode("p", null, "你好," + _toDisplayString(_ctx.name), 1 /* TEXT */)
          ]))
        }
        最后一个_createVNode中有个数字1,就是静态标记
        
    2. hoistStatic 静态提升:

      • Vue2.x中无论元素是否参与更新,每次都会重新创建
      • Vue3.0中对于不参与更新的元素,只会被创建一次,之后会在渲染时被复用
        静态提升之前:
        
        export function render(_ctx, _cache, $props, $setup, $data, $options) {
          return (_openBlock(), _createBlock("div", null, [
            _createVNode("p", null, "你好,小明"),
            _createVNode("p", null, "你好,小明"),
            _createVNode("p", null, "你好,小明"),
            _createVNode("p", null, "你好," + _toDisplayString(_ctx.name), 1 /* TEXT */)
          ]))
        }
        
        静态提升之后:
        
        const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "你好,小明", -1 /* HOISTED */)
        const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "你好,小明", -1 /* HOISTED */)
        const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "你好,小明", -1 /* HOISTED */)
        
        export function render(_ctx, _cache, $props, $setup, $data, $options) {
          return (_openBlock(), _createBlock("div", null, [
            _hoisted_1,
            _hoisted_2,
            _hoisted_3,
            _createVNode("p", null, "你好," + _toDisplayString(_ctx.name), 1 /* TEXT */)
          ]))
        }
        
    3. cacheHandlers 事件侦听器缓存:

      • 默认情况下onClick会被视为动态绑定,所以每次都会追踪它的变化。
        但因为是同一个函数,所以没有追踪变化,直接缓存服用。
      <div>
        <button @click="onClick">按钮</button>
      </div>
      事件监听缓存之前:
        export function render(_ctx, _cache, $props, $setup, $data, $options) {
          return (_openBlock(), _createBlock("div", null, [
            _createVNode("button", { onClick: _ctx.onClick }, "按钮", 8 /* PROPS */, ["onClick"])
          ]))
        }
      事件监听缓存之后:
      export function render(_ctx, _cache, $props, $setup, $data, $options) {
        return (_openBlock(), _createBlock("div", null, [
          _createVNode("button", {
            onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick && _ctx.onClick(...args)))
          }, "按钮")
        ]))
      }
      
    4. ssr 渲染:

      • 当有大量静态的内容时候,这些内容会被当做纯字符串推进一个buffer里面,即使存在动态的绑定,会通过模板插值嵌入进去。这样会比通过虚拟DOM来渲染的快上很多很多。

      • 当静态内容大到一定量级时候,会用 _createStaticVNode 方法在客户端去生成一个static node,这些静态的node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。

    创建Vue3.0项目

    • Vue-CLI的方式:

      • npm install -g @vue/cli
      • vue create projectName
      • cd projectName
      • npm install
      • vue add vue-next (如果VUCLI的版本比较低,会安装失败,安装最新版本VUECLI即可) 现在vue cli 默认支持 vue3.0,所以可以省略该步骤
      • npm run serve
    • Vite方式:

      • npm install -g create-vite-app
      • create-vite-app projectName(项目名称)
      • cd projectName
      • npm install
      • npm run serve

    组合API (composition API)

      setup() 函数

    • 该方法是在 beforecreate 钩子之前完成的

    • 是组合API的入口,该函数执行时尚未创建组件实例,所以没有this。

    • 在组合API中定义的变量/方法,想在外界使用,必须通过 return 暴露。

    • 如果函数返回对象,对象中的变量/方法,可以直接在模板中使用。

    • 函数只能监听简单类型的变化,不能监听复杂类型的变化(对象/数组)

    • 函数只能是同步的,不能是异步的

      ref

    • 作用:定义一个响应式数据。
    • 语法:const xxx = ref(初始值)
    • 在js中使用ref的值必须通过value获取
    • 在模板中使用不用通过value获取
    • 修改响应式数据(( 值类型 / 对象的属性 / 数组的某个值 ))是不会影响到原始数据的
    <template>
      <div class="home">
        <p>{{count}}</p>
        <button @click="myFn">按钮</button>
      </div>
    </template>
    
    <script>
    import { ref } from "vue";
    export default {
      name: 'Home',
      setup(){
        // 定义一个count变量,初始值为0
        let count = ref(0);
        // 在组合API中,如果想定义方法,不用定义到methods中,直接定义即可。
        function myFn(){
          count.value += 1;
        }
        //注意点:在组合API中定义的变量/方法,要想在外界使用,必须通过return {xxx,xxx} 暴露出去
        return {count,myFn}
      }
    }
    </script>
    

      reactive

    • 是Vue3中提供的实现响应式数据的方法,本质:将传入的数据包装成一个Proxy对象

    • Vue2.x中响应式数据是通过defineProperty来实现的

    • Vue3中响应式数据是通过ES6的Proxy来实现的

    • 参数必须是对象(json/array)

    • 如果给reactive传递了其它对象(其它类型数据):

      1. 默认情况下修改对象,界面不会自动更新
      2. 如果想更新,可以通过重新赋值的方式
    <template>
      <div class="home">
        <p>{{stateage.time}}</p>
        <button @click="myFn">按钮</button>
        <ul>
          <li v-for="(stu,index) in state.stus" :key="stu.id" 
          @click="removeStu(index)">{{stu.name}} -- {{stu.age}}</li>
        </ul>
      </div>
    </template>
    
    <script>
    import { reactive } from "vue";
    export default {
      name: 'Home',
      // setup函数是组合API的入口函数
      setup(){
        // 创建一个相应式数据
        // 本质:将传入的数据包装成一个 Proxy 对象。
    
        // let stateage = reactive(123);      // 普通数据类型
    
        // let stateage = reactive([1,2,3])  // 数组
    
        // let stateage = reactive({         // json 对象
        //   age:10
        // });
    
        let stateage = reactive({
         time:new Date()
        })  // 其它对象 
        function myFn(){
          // stateage = 666     // 由于创建时不是一个对象,所以无法实现响应式。
    
          // stateage[0] += 1;  // 可以实现响应式 
    
          // stateage.age += 1; // 可以实现响应式
          
          // 修改以前的,界面不会更新
          stateage.time.setDate(stateage.time.getDate() + 1);
          // 重新赋值
          const newTime = new Date(stateage.time.getTime());
          newTime.setDate(stateage.time.getDate() + 1);
          stateage.time = newTime;
          console.log(stateage.time)
        }
        
        // 第一种写法:
        // let state = reactive({
        //   stus:[
        //     {id:1,name:"张三",age:10},
        //     {id:2,name:"李四",age:20},
        //     {id:3,name:"王五",age:30},
        //   ]
        // });
        // function removeStu(index){
        //   state.stus = state.stus.filter((stu,idx) => idx !== index);
        // }
    
        // 第二种写法:
        let {state,removeStu} = useRemoveStudent();
        return {state,removeStu,stateage,myFn}
      }
    }
    function useRemoveStudent(){
      let state = reactive({
        stus:[
          {id:1,name:"张三",age:10},
          {id:2,name:"李四",age:20},
          {id:3,name:"王五",age:30},
        ]
      });
      function removeStu(index){
        state.stus = state.stus.filter((stu,idx) => idx !== index);
      }
      return {state, removeStu}
    }
    </script>
    

      isRef 与 isReactive

    • isRef 方法可以判断数据是否是 ref 对象
    • isReactive 方法可以判断数据是否是 reactive 对象
      // 判断是否是 ref 对象
      function isRef(obj){
    
        // 如果是 ref 对象 返回 true ,不是返回 false
        // return Boolean(obj && obj.__v_isRef === true);
    
        // 如果是 ref 对象 返回 true ,不是返回 undefined
        return obj && obj.__v_isRef;
      }
    
      // 判断是否是 reactive 对象
      function isReactive(obj){
    
        // 如果是 reactive 对象 返回 true ,不是返回 false
        // return Boolean(obj && obj.__v_isReactive === true);
    
        // 如果是 reactive 对象 返回 true ,不是返回 undefined
        return obj && obj.__v_isReactive;
      }
    
      // 测试
      console.log(isRef(ref(0)))             // true   
      console.log(isRef(reactive({})))       // false
      console.log(isReactive(ref(0)))        // false 
      console.log(isReactive(reactive({})))  // true
    
      <template>
        <div class="home">
          <div>{{age}}</div>
          <div>{{name.value}}</div>
          <button @click="myFn">按钮</button>
        </div>
      </template>
    
      <script>
      import {isRef,isReactive, reactive,ref} from "vue";
      export default {
        name: 'Home',
        setup(){
    
          let age = ref(18);
          let name = reactive({
            value:"小明"
          })
          function myFn(){
            console.log(isRef(age));       // true
            console.log(isRef(name));      // false
            console.log(isReactive(age));  // false
            console.log(isReactive(name)); // true
            age.value += 1;
            name.value = "小张";
          }
          return { age, name, myFn }
    
        }
      }
      </script>
    

      递归监听

    • 默认情况下,无论是通过ref和reactive都是递归监听
    • 问题:数据量较大时,非常耗性能
    递归监听
    <template>
      <div class="home">
        <p>{{stateref.a}}</p>
        <p>{{stateref.gf.b}}</p>
        <p>{{stateref.gf.f.c}}</p>
        <p>{{stateref.gf.f.s.d}}</p>
        <p>------------------------</p>
        <p>{{statereact.a}}</p>
        <p>{{statereact.gf.b}}</p>
        <p>{{statereact.gf.f.c}}</p>
        <p>{{statereact.gf.f.s.d}}</p>
        <p>--------------------</p>
        <button @click="myFn">按钮</button>
      </div>
    </template>
    
    <script>
    import {reactive,ref} from "vue";
    export default {
      name: 'Home',
      setup(){
        let stateref = ref({
          a:"a",
          gf:{
            b:"b",
            f:{
              c:"c",
              s:{
                d:"d"
              }
            }
          }
        });
        let statereact = reactive({
          a:"a",
          gf:{
            b:"b",
            f:{
              c:"c",
              s:{
                d:"d"
              }
            }
          }
        });
        function myFn(){
          stateref.value.a = 1;
          stateref.value.gf.b = 2;
          stateref.value.gf.f.c = 3;
          stateref.value.gf.f.s.d = 4;
    
          statereact.a = "1";
          statereact.gf.b = "2";
          statereact.gf.f.c = "3";
          statereact.gf.f.s.d = "4";
        }
    
        return { stateref, statereact, myFn}
      }
    }
    </script>
    

      shallowReactive 和 shallowRef、triggerRef

    • shallowReactive 和 shallowRef 可以实现非递归监听,只监听数据的第一层的变化

    • shallowRef 的本质:shallowRef -> shallowReactive。即:shallowRef(10) -> shallowReactive({ value:10 })

    • 注意点:如果通过 shallowRef 创建的数据,vue监听的是 .value 的变化,并不是数据的第一层的变化,因为本质上 value 才是第一层。

    • triggerRef 可以实现更改 shallowRef 中非第一层的数据并更新页面。

    • 注意点:vue3 只提供了 triggerRef 方法,没有提供 triggerReactive 方法,所以如果是 reactive 类型的数据,那么是无法主动触发界面更新的。

      toRaw 和 markRaw

    • toRaw:从 Reactive 或 Ref 中得到原始数据。

    • 作用:做一些不想被监听的事情 ( 提升性能 )

    • 注意点:如果想通过 toRaw 拿到 ref 类型的原始数据(创建传入的数据),就必须明确告诉 toRaw 方法,要获取的是 .value 的值,因为经过vue处理之后,.value 中保存的才是当初创建时传入的原始数据。

      import  {  toRaw, reactive, ref } from "vue";
    
      export default {
        setup(){
    
          let obj = {name:'lnj',age:18};
          let state = reactive(obj);
          let obj2 = toRaw(state);
    
          console.log(obj2 == obj)       // true
          console.log(obj === state);    // false
          console.log(obj == state);     // false
    
    
          // let state = ref(obj);
          
          // let obj2 = toRaw(state);
          // console.log(obj2 === obj)   // false
    
          // let obj2 = toRaw(state.value)
          // console.log(obj2 === obj)      // true
      
        }
      }
    
    • state和obj的关系:引用的关系,state的本质是一个 Proxy 对象,在这个 Proxy 对象中引用了 obj。
    • 如果直接修改obj,是无法触发界面更新的。只有通过包装之后的对象来修改,才会触发界面的更新。
    • markRaw:使 Reactive 或 Ref 无法将数据创建(转化)为响应式数据
    • 作用:将数据变为不可被追踪监听的非响应式数据。

      toRef 和 toRefs

    • ref:如果利用 ref 将定义的数据( 值类型 / 对象的属性 / 数组的某个值 )变成响应式的数据,修改响应式数据是不会影响到原始数据的。会触发UI界面更新。

    • toRef:如果利用 toRef 将定义的数据( 值类型 / 对象的属性 / 数组的某个值 )变成响应式数据,修改响应式数据是会影响到原始数据的。但是如果响应式数据是通过 toRef 创建的,那么修改了数据并不会触发UI界面的更新。

    • toRefs:可以同时监听整个对象的属性 / 数组,改变响应式数据时,会改变原始数据,不会触发UI更新。

      customRef

    • 返回一个 ref 对象,可以显示地依赖和触发响应

    • 注意点:不能在get方法中发送网络请求

    import {customRef} from "vue";
    
    function myRef(value){
      return customRef((track,trigger)=>{
        return {
          get(){
            track(); // 告诉 vue 这个数据是需要追踪变化的
            console.log('get',value);
            return value
          },
          set(newvalue){
            console.log('set',newvalue);
            value = newvalue;
            trigger(); // 告诉vue触发界面更新
          }
        }
      })
    }
    export default {
      setup(){
        let age = myRef(18);
        function myFn(){
          age.value += 1;
        }
    
        return {state,myFn}
      }
    }
    

      ref 获取元素

    • vue2.x 中我们可以通过给元素添加 ref='xxx' 然后在代码中通过 refs.xxx 的方式来获取元素
    • 在 vue3.x 中我们也可以通过 ref 来获取元素
    <template>
      <div class="ref_get">
        <div ref="box">我是div</div>
      </div> 
    </template>
    
    <script>
    
    import {ref,onMounted} from "vue";
    // onMounted 监听dom是否渲染完成
    export default {
      setup(){
        let box = ref(null);
        onMounted(()=>{
          console.log('onMounted',box.value);
        })
        console.log(box.value);
        return {box}
      }
    }
    </script>
    

      readonly 和 isReadonly、shallowReadonly

    • readonly:用于创建一个只读数据,并且是递归只读

    • shallowReadonly:用于创建一个只读的数据,但不是递归只读,只是数据第一层只读。

    • isReadonly:判断数据是否是只读的。

    • constreadonly 区别:

      • const:赋值保护,不能给变量重新赋值

      • readonly:属性保护,不能给属性重新赋值。

    <template>
      <div class="readonly">
        <button @click="myFn">按钮</button>
      </div>
    </template>
    
    <script>
    import {readonly, isReadonly, shallowReadonly} from "vue"
    export default {
      setup(){
        let state = readonly({
          name:'lng',
          attr:{
            age:18,
            height:180
          }
        });
        let shallstate = shallowReadonly({
          name:'lng',
          attr:{
            age:18,
            height:180
          }
        });
        console.log(isReadonly(state));
        function myFn(){
          // state.name = "zs";   // 修改失败,警告
          // state.attr.age = 20; // 修改失败,警告
          // shallstate.name = "zs"; // 修改失败,警告
          shallstate.attr.age = 20;  // 修改成功
          console.log(shallstate.attr.age);
        }
        return { state,shallstate,myFn }
      }
    }
    </script>
    

      手写组合API

    • reactive
    <script>
    export default {
      setup(){
    
        function ref(val){
          return reactive({value:val})
        }
    
        function reactive(obj){
          if(typeof obj === 'object'){
            if(obj instanceof Array){
              /**
               * 如果是一个数组,那么取出数组中的每一个元素
               * 判断每一个元素是否又是一个对象,如果又是一个对象,那么也需要包装成 Proxy
               */
              obj.forEach((item,index) => {
                if(typeof item == 'object'){
                  obj[index] = reactive(item)
                }
              })
            }else{
              /**
               * 如果是一个对象,那么取出对象中的每一个属性的值
               * 判断每一个属性的值是否又是一个对象,如果又是一个对象,那么也需要包装成 Proxy
               */
              for (const key in obj) {
                let item = obj[key];
                if(typeof item == 'object'){
                  obj[key] = reactive(item);
                }
              }
            }
            return new Proxy(obj,{
              get(obj,key){
                return obj[key]
              },
              set(obj,key,value){
                obj[key] = value;
                console.log('更新UI界面')
                return true
              }
            })
          }else{
            console.warn(`message:${obj} is not object`)
          }
        }
      }
    }
    </script>
    
    • shallowReadonly
    function shallowReadonly(obj){
      return new Proxy(obj,{
        get(obj,key){
          return obj[key]
        },
        set(obj,key,val){
          console.warn(`message:${obj} 的 ${key} is onlyread`)
        }
      })
    }
    
    • shallowRef 和 shallowReactive
    function shallowRef(val){
      return shallowReactive({value:val})
    }
    
    
    function shallowReactive(obj){
      return new Proxy(obj,{
        get(obj,key){
          return obj[key]
        },
        set(obj,key,value){
          obj[key] = value;
          return true
        }
      })
    }
    
  • 相关阅读:
    poj3278 Catch That Cow
    poj2251 Dungeon Master
    poj1321 棋盘问题
    poj3083 Children of the Candy Cor
    jvm基础知识—垃圾回收机制
    jvm基础知识1
    java面试基础必备
    java soket通信总结 bio nio aio的区别和总结
    java scoket aIO 通信
    java scoket Blocking 阻塞IO socket通信四
  • 原文地址:https://www.cnblogs.com/aloneer/p/14322006.html
Copyright © 2011-2022 走看看