vue-cli创建
vue create [project_name]
vite创建
npm init @vitejs/app [project_name]
npm install
项目结构
import { createApp } from 'vue';
import App from './App.vue';
createApp(app).mount('#app');
Composition API
组合式api。
Vue2是Options API。
(1)setup
- 在beforeCreate之前就执行一次。
- 尽量不要和vue2中的data、methods、computed、watch…混用。
- vue2中的data、methods、computed、watch可以访问到setup中的属性方法,反之setup不能访问到vue2中的。
- 如果变量、函数重名,setup优先。
- this = undefined
(2)ref
- 定义一个响应式数据,将传入的值包装成引用对象(Reference Implement)。
- 基本数据类型用Object.defineProperty实现,引用类型数据用reactive函数实现。
- 操纵数据需要.value,模板中读取数据不需要.value。
(3)reactive
- 定义一个对象类型的响应式数据。
- 用proxy实现。
- 操纵数据和模板中读取数据不需要.value。
(4)computed
(5)watch
(6)watchEffect
<template>
<div>{{name}}</div>
<div>{{age}}></div>
<button @click="changeInfo"></button>
</template>
<script>
import { ref, reactive, computed, watch, watchEffect } from 'vue';
export default{
name: 'component',
props: ['msg', 'school'],
emits: ['hello'],
setup(props, context){
let name = ref('张三');
let age = ref(18);
let job = reactive({
type: '前端工程师',
salary: '30k'
});
let hobby = reactive(['抽烟', '喝酒', '烫头']);
function changeInfo(){
name.value = '李四';
age.value = 19;
job.type = '后端工程师';
hobby[0] = '学习';
}
let person = reactive({
firstName: '张',
lastName: '三'
});
person.fullName = computed(()=>{
get(){
return person.firstName + '-' +person.lastName;
},
set(value){
const names = value.split('-');
person.firstName = names[0];
person.lastName = names[1];
}
});
let sum = ref(0);
let msg = ref('msg');
watch(sum, (newValue, oldValue)=>{
...
});
watch([sum, msg], (newValueArr, oldValueArr)=>{
...
}, {immediate: true});
watch(person, (newValue, oldValue)=>{
...
});
watch(()=>person.name, (newValue, oldValue)=>{
...
});
watch([()=>person.name, ()=>person.age], (newValueArr, oldValueArr)=>{
...
})
watch(()=>person.job, (newValue, oldValue)=>{
...
}, {deep: ture});
watchEffect(()=>{
});
return {
name,
age,
changeInfo,
person
}
}
}
</script>
(7)toRef、toRefs
setup(){
...
const name = toRef(person, 'name');
const salary = toRef(person.job.j1, 'salary');
return{
...toRefs(person)
}
}
(8)shallowRef
类似Ref,基本数据类型能实现响应式,引用数据类型直接不处理。
(9)shallowReactive
只考虑第一层的响应数据。
(10)readonly
参数为ref或者reactive处理后的。
(11)shallowReadonly
(12)toRaw
把响应式数据变成普通数据。
(13)markRow
标记一个对象,使其永远不会再变成响应式对象。 给对象添加非响应式的数据。
(14)customRef
创建自定义ref,并对其依赖项跟踪和更新触发进行显式控制。
<template>
<input type="text" v-model="keyword">
<h3>{{keyword}}</h3>
</template>
<script>
import {ref, customRef} from 'vue';
export default{
name: 'app',
setup(){
let keyword = myRef('hello', 1000);
function myRef(value, delay){
let timer;
return customRef((track, trigger)=>{
return {
get(){
track(); // 追踪数据数据的变化
return value;
},
set(newValue){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
value = newValue;
trigger(); // 通知vue重新解析模板
}, delay);
}
}
})
}
return{
keyword
}
}
}
</script>
响应式数据的判断
(1)isRef
检查一个值是否为ref对象。
(2)isReactive
检查一个对象是否由reactive创建的响应式代理。
(3)isReadonly
检查一个对象是否由readonly创建的只读代理。
(4)isProxy
检查一个对象是否由reactive或readonly方法创建的代理。
响应式原理
通过proxy拦截对象中任意属性的变化。 通过reflect对源对象的属性进行操作。
let p = new Proxy(person, {
get(target, propName){
return Reflect.get(target, propName);
},
set(target, propName, value){
Reflet.set(target, propName, value);
},
deleteProperty(target, propName){
return Reflet.deleteProperty(target, propName);
}
});
生命周期
beforeCreate Created beforeMount Mounted beforeUpdate Updated beforeUnmount Unmounted
<script>
/*
生命周期 => 组合式API
beforeCreate => setup()
created => setup()
beforeMount => onBeforeMount
mounted => onMounted
beforeUpdate => onBeforeUpdate
updated => onUpdated
beforeUnmount => onBeforeUnmount
unmounted => onUnmounted
*/
import {ref, onBeforeMount } from 'vue';
export default{
name: 'demo',
setup(){
onBeforeMount(()=>{
...
});
}
}
</script>
自定义hook
本质是一个函数,把setup()中的一些逻辑操作进行封装,供多个组件复用。
export default function(){
...
return data;
}
<script>
import {ref} from 'vue';
import usePoint from '../hooks/usePoint';
export default{
setup(){
...
let point = usePoint();
...
}
}
</script>
provide、inject
setup(){
...
let car = reactive({name: 'a', price: 1});
provide('car', car);
...
}
setup(){
let car = inject('car');
}
组件
(1)Fragment
在vue2中组件必须有一个根标签。 在vue3中组件可以没有根标签,内部将多个标签包含在一个Fragment虚拟元素中。
减少标签层级,减少内存占用。
(2)Teleport
<template>
// to="#a"
<teleport to="body">
...
</teleport>
</template>
(3)Suspendse
<template>
<div class="app">
<h3>app组件</h3>
<Suspense>
<template v-slot:default>
<Child/>
</template>
<template v-slot:fallback>
<h3>loading...</h3>
</template>
</Suspense>
</div>
</template>
<script>
// 异步引入组件
import {defineAsyncComponent} from 'vue';
const Child = defineAsyncComponent(()=>import('./components/Child.vue'));
</script>
|