乐趣区

关于vue.js:Vue3x学习纪录

1. Vue2 到 Vue3

vue3 我的项目搭建

  • 1. 装置 vue3 的 cli
    cnpm i -g @vue/cli@next

    @next 是因为没有正式公布,前面正式公布可能会去掉

    2. 创立 vue3 我的项目
    vue create <name>

    3.vue3 我的项目


    vue3 跟 vue2 差不多 多了一个composition API

    vue3 和 ts 的配合更好了

vue3 与 vue2 的区别

Vue3 与 Vue2 的不同:1.vue 实例化形式变了

//vue2
import Vue from 'vue';
import App from './App.vue';

new Vue({render: h => h(App)
}).mount('#app');

//vue3
import {createApp} from 'vue';
import App from './App.vue';
createApp(App).mount('#app');

2.Vue 全局办法变了
//vue2
import Vue from 'vue';
Vue.component('name', {});

//vue3
import {createApp} from 'vue';
let app=createApp(App);
app.component('name', {});
app.mount('#app');


3.vue3 勾销了 filter 用 computed、函数代替

4.v-model
//vue2
v-model = :value + @input

//vue3
[html 组件]
v-model = :value + @input

[自定义组件]
v-model = :modelValue + @update:modelValue


5. 函数组件的写法变了
//vue2
render(h){return h(...);
}

//vue3
import {h} from 'vue';
render(props, context){return h(...);
}


6.data 变了
//vue 的 data 对立了,只有函数一种
data(){return {};
}

7. 异步组件(分包加载)//vue2
const cmp1=()=>import('./cmp1');

//vue3
import {defineAsyncComponent} from 'vue';
const cmp1=defineAsyncComponent(()=>import('./cmp1'));

8.vue3 事件简化了
//vue2
this.$emit('name', ...);
this.$on();
this.$off();
this.$once();

//vue3
this.$emit('name', ...);

9. 其余
自定义 directive 变了——beforeMount、mounted、beforeUpdate、updated、...
template 不须要根元素

2. 详解 composition API

composition API 到底是什么

​ 1. 数据、办法、computed 注入到一个组件当中

​ 2. 重用组件的代码 —vue2.x 种组件外面货色特地多、特地乱(data、method、computed、…)


​ composition API——注入
​ 把货色(数据、办法、computed、生存周期函数、…)注入到组件当中——集中到一个中央写


// 一般形式
export default {data(){a: 12},
  methods: {fn(){....}
  },
  computed: {}}
//composition API
export default {setup(){
    return {
      a: 12,
      fn(){...},
    }
  }
}

setup、可响应数据—reactive

  1. setup
    beforeCreate
    setup
    created

    setup 执行程序是在 beforeCreate 之后 created 之前,这个时候组件刚刚被 new 进去,组件外面什么也没有,所以无奈应用 this 及其他的货色

    setup 无奈应用组件的其余货色(data、methods、computed、…)、也不要应用 this

    setup 执行的过程中,组件中其余货色都没有创立;不能用 this
    setup 是同步的(不能用 async)

  2. 可响应数据
    一般的变量,无奈实现响应操作(检测到数据变动,从新渲染组件)

    应用可响应数据(reactive)

    import {reactive} from "vue";
    const state = reactive({
        xxx:xxx,
        xxx:xxx
    })

    reactive的参数必须是一个 object

    reactive(number|string|boolean) ×
    reactive({...}|[...]) √

    必须是对象(json、数组)如果是其余对象(Date、RegExp、…),批改不会被监听(proxy 的起因),如果非要应用能够创立一个新的来笼罩。例如:

    <template>
      <div>a={{a.date}}</div>
      <button type="button" @click="fn">++</button>
    </template>
    
    <script>
    import {reactive} from "vue";
    
    export default {setup() {const a = reactive({ date: new Date() });
        return {
          a,
          fn() {
            // 这样批改数据扭转页面不会刷新
            // a.date.setDate(a.date.getDate() + 1);
            
            // 须要间接笼罩
            const newDate = new Date(a.date.getTime() + 86400000);
            a.date = newDate;
            console.log(a.date);
          },
        };
      },
    };
    </script>

ref、readonly

  1. ref

    1. 应用根本类型

      • 应用

        isRef判断一个值是不是 ref

        import {ref, isRef} from "vue";
        let a = ref(12);  // 根本等价于 reactive({value: 12}),只是会主动加 value
        console.log(isRef(a)); //true - 判断是否 ref

        template 中 ref 会主动加.value,例如应用 a

        <template>{{a}}</template>

        在 js 中须要本人加.value 例如本人批改

        <script>fn(){ a.value++}</script>

    2. 援用节点(html 原生、自定义组件)

      <template>
        <div ref="a">dsfasdfdas</div>
      </template>
      <script>
      import {ref, onMounted} from "vue";
      export default {setup() {const a = ref(null);
      
          // 须要在 onMounted 中应用,不然在 setup 执行过程中 a 是不存在
          onMounted(() => {a.value.style.border = "1px solid black";});
      
          return {a,};
        },
      };
      </script>
  2. readonly

    相似于const,不同的是:readonly 爱护所有操作、递归爱护; const—- 仅爱护赋值、非递归

    isReadonly判断一个值是不是 readonly

    <template>
      {{a.count}}
      <button type="button" @click="a.count++">++</button>
    </template>
    
    <script>
    import {readonly, isReadonly} from "vue";
    
    export default {setup() {const a = readonly({ count: 12});
        // a.count++ 的时候 const 会报正告,readonly 是递归爱护多层 
          
        // 判断一个值是不是 readonly
        console.log(isReadonly(a)); //true
          
        // const a = {count: 5};
        // a.count++ 的时候 const 会减少,const 只爱护赋值操作,只爱护一层
    
        return {a};
      },
    };
    </script>

递归监听、shallow、trigger

  1. 递归监听(深度监听)

    在 vue2.x 中批改对象属性页面是无奈实现刷新的,例如 this.data.obj.a = 12 页面并不会刷新(须要应用 $set),vue3.x 中实现了递归监听,批改data.obj.a = 12 页面也会刷新

  2. shallow&trigger

    vue3 递归监听的实现原理是把多层数据全副改为Proxy,例如:

    import {reactive, shallowRef, triggerRef} from "vue";
    // reactive、ref、readonly 都是递归监听,这里应用 ref 举例
    // 非递归版本
    // shallowReactive
    // shallowRef
    // shallowReadonly
    export default {setup(){
            const json = reactive({arr:[ { a:12} ]
            });
            console.log(json); // Proxy
            console.log(json.arr); // Proxy
            console.log(json.arr[0]); // Proxy
            
            return {json}
        }
    }

    当数据特地宏大时,例如几万、几十万条数据时,性能可能会有影响(一般对象转成 proxy), 这个须要应用非递归版本,例如:

    import {shallowRef, triggerRef} from "vue";
    export default {setup(){
            const json = shallowRef({arr: [ { a:12} ]
            })
            console.log(json); // Proxy
            console.log(json.arr); // [...]
            console.log(json.arr[0]); // {...}
            
            setTimeout(()=>{json.value.arr[0].a++;
              console.log(json.value.arr[0].a);
              // 如果没有这一行,数据变,页面不会刷新
              triggerRef(json); // 告诉页面刷新
            }, 500)
            
            return {json}
        }
    }

raw 原始数据

  1. toRaw

    如果数据有大量的操作,始终被监听可能会影响性能,能够先把数据转换成原始数据,改完之后再变回去

    //reactive、ref、readonly -> 原始数据
    let json = reactive({...}; //proxy
    let obj = toRow(json);  // {...}
    // 原始数据 ->  reactive、ref、readonly
    reactive(obj); //proxy

    把创立 reactive、ref 的参数返回来 对原始数据进行操作,不会被监听的(性能高)

  2. markRaw 放弃一个数据永远是原始的

    可能写库的时候会用,数据不会被转成 proxy,比方返回一个数据,不心愿这个数据被监听

    let json = markRaw({xxx:xxx});
    reactive(json); // object 不会被转成 proxy

深刻 ref 操作

  1. unRef 或如 ref 的原始数据

    例如let res = ref(12);

    应用 toRaw 获取 => {value:12}

    应用 unRef 获取 => 12

    toRaw是连着 value 一块获取的,unRef 是 ref 专用的

  2. toRef

    const json = {a:12};
    let res = ref(json.a);
    
    res.value = 13;
    // 这个时候 res 的 value 会变为 13,然而 json 的内容不会变,相当于 ref 和原始数据没有关系,// let res = ref(json.a) 等价于 let res = ref(12);
    
    //toRef
    let res = toRef(json, "a");
    res.value = 13;
    // 这个时候 res 的 value 和 json 的 a 都会变为 13,然而页面不会刷新
    
    // ref - 一般 ref 对象
    //    1. 不会跟原始数据挂钩
    //    2. 会触发页面渲染
    // toRef - 非凡的 ref 对象
    //    1. 创立的 ref 对象,跟原始数据对象挂钩
    //    2. 不会触发渲染
    ref toRef
    跟原始数据无关(相当于复制) 会援用原始数据(改的话都会变)
    会触发页面渲染 不会触发页面渲染
  3. toRefs

    相当于 toRef 的批量操作

    const json = {a:12, b:5}
    // toRef
    let res1 = toRef(json, "a");
    let res2 = toRef(json, "b");
    
    // toRefs
    let res = toRefs(json)
    // 相当于://toRefs({a: xx, b: xxx}) => {a: toRef(json, 'a'), b: toRef(json, 'b')}
  4. customRef – 自定义 ref

    function myRef(...){
        //code...
        return customRef((track, trigger)=>{
            // track == 整个 ref 开始
            // trigger == 流程完结,告诉 vue 渲染
            return {get(){track();
                    return xxxx;
                },
                set(newVal){
                    // code..
                    trigger();}
            }
        })
    }
    
    setup(){
        // 返回的内容就是一般的 ref 对象
        let data = myRef(...);
    }
退出移动版