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实例化形式变了//vue2import Vue from 'vue';import App from './App.vue';new Vue({ render: h => h(App)}).mount('#app');//vue3import { createApp } from 'vue';import App from './App.vue';createApp(App).mount('#app');2.Vue全局办法变了//vue2import Vue from 'vue';Vue.component('name', {});//vue3import {createApp} from 'vue';let app=createApp(App);app.component('name', {});app.mount('#app');3.vue3勾销了filter 用computed、函数代替4.v-model//vue2v-model = :value + @input//vue3[html组件]v-model = :value + @input[自定义组件]v-model = :modelValue + @update:modelValue5.函数组件的写法变了//vue2render(h){ return h(...);}//vue3import {h} from 'vue';render(props, context){ return h(...);}6.data变了//vue的data对立了,只有函数一种data(){ return {};}7.异步组件(分包加载)//vue2const cmp1=()=>import('./cmp1');//vue3import {defineAsyncComponent} from 'vue';const cmp1=defineAsyncComponent(()=>import('./cmp1'));8.vue3事件简化了//vue2this.$emit('name', ...);this.$on();this.$off();this.$once();//vue3this.$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 APIexport default { setup(){ return { a: 12, fn(){ ... }, } }}
setup、可响应数据—reactive
- setup
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
的参数必须是一个objectreactive(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
ref
应用根本类型
应用
isRef
判断一个值是不是refimport { ref, isRef } from "vue";let a = ref(12); //根本等价于 reactive({ value: 12 }),只是会主动加valueconsole.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>
递归监听、shallow、trigger
- 递归监听(深度监听)
在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// shallowReadonlyexport 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原始数据
toRaw
如果数据有大量的操作,始终被监听可能会影响性能,能够先把数据转换成原始数据,改完之后再变回去
//reactive、ref、readonly -> 原始数据let json = reactive({ ... }; //proxylet obj = toRow(json); // {...}//原始数据 -> reactive、ref、readonlyreactive(obj); //proxy
把创立reactive、ref的参数返回来 对原始数据进行操作,不会被监听的(性能高)
markRaw 放弃一个数据永远是原始的
可能写库的时候会用,数据不会被转成proxy,比方返回一个数据,不心愿这个数据被监听
let json = markRaw({xxx:xxx});reactive(json); // object 不会被转成proxy
深刻ref操作
- unRef 或如ref的原始数据
例如
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);//toReflet 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 }// toReflet res1 = toRef(json, "a");let res2 = toRef(json, "b");// toRefslet 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(...);}