Vue3.x學習紀錄

1. Vue2到Vue3

vue3項目搭建

  • 1.安裝vue3的cli
    cnpm i -g @vue/cli@nextjavascript

    @next 是由於沒有正式發佈,後面正式發佈可能會去掉html

    2.建立vue3項目
    vue create <name>vue

    3.vue3項目java


    vue3跟vue2差很少 多了一個composition APIreact

    vue3和ts的配合更好了npm

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注入到一個組件當中 json

​ 2.重用組件的代碼---vue2.x種組件裏面東西特別多、特別亂(data、method、computed、...)數組


​ composition API——注入
​ 把東西(數據、方法、computed、生存周期函數、...)注入到組件當中——集中到一個地方寫app


//普通方式
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(...);
    }
相關文章
相關標籤/搜索