1.安裝vue3的clicnpm i -g @vue/cli@next
javascript
@next 是由於沒有正式發佈,後面正式發佈可能會去掉html
2.建立vue3項目vue create <name>
vue
3.vue3項目java
vue3跟vue2差很少 多了一個composition API
react
vue3和ts的配合更好了npm
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不須要根元素
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(){ ... }, } } }
beforeCreate
setup
created
setup執行順序是在beforeCreate
以後created
以前,這個時候組件剛剛被new出來,組件裏面什麼也沒有,因此沒法使用this
及其餘的東西異步
setup沒法使用組件的其餘東西(data、methods、computed、...)、也不要使用this
setup執行的過程當中,組件中其餘東西都沒有建立;不能用this
setup是同步的(不能用async)
可響應數據
普通的變量,沒法完成響應操做(檢測到數據變化,從新渲染組件)
使用可響應數據(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
使用基本類型
使用
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>
引用節點(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>
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>
在vue2.x中修改對象屬性頁面是沒法完成刷新的,例如this.data.obj.a = 12
頁面並不會刷新(須要使用$set
),vue3.x中實現了遞歸監聽,修改data.obj.a = 12
頁面也會刷新
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} } }
toRaw
若是數據有大量的操做,一直被監聽可能會影響性能,能夠先把數據轉換成原始數據,改完以後再變回去
//reactive、ref、readonly -> 原始數據 let json = reactive({ ... }; //proxy let obj = toRow(json); // {...} //原始數據 -> reactive、ref、readonly reactive(obj); //proxy
把建立reactive、ref的參數返回來 對原始數據進行操做,不會被監聽的(性能高)
markRaw 保持一個數據永遠是原始的
可能寫庫的時候會用,數據不會被轉成proxy,好比返回一個數據,不但願這個數據被監聽
let json = markRaw({xxx:xxx}); reactive(json); // object 不會被轉成proxy
例如let res = ref(12);
使用toRaw獲取 => { value:12 }
使用unRef獲取 => 12
toRaw
是連着value一塊獲取的,unRef是ref專用的
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 |
---|---|
跟原始數據無關(至關於複製) | 會引用原始數據(改的話都會變) |
會觸發頁面渲染 | 不會觸發頁面渲染 |
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')}
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(...); }