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(...); }