预备知识:
vue3亮点
1.性能比vue2.x快;
2.按需编译,体积变小;
3.组合api 类似与react hooks;
4.更好的ts支持
5.暴露了自定义渲染api
6.更先进的组件;
vue是如何变快的?
1.diff算法优化;
vue 2.x 采用的diff算法是,全量对比;
vue 3 采用diff算法是,只对比待有静态标志符的;
2.静态提升
vue2.x不论元素是否参与更新,每次重新创建,然后再渲染;
vue3中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可;
怎么提升的?
静态提升之前:
import { toDisplayString as _toDisplayString, createVNode as _createVNode, createTextVNode as _createTextVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createTextVNode(" Hello World! "),
_createVNode("p", null, _toDisplayString(_ctx.msd), 1 /* TEXT */),
_createVNode("p", null, "ffff"),
_createVNode("p", null, "ffffww")
]))
}
静态提升之后:
import { toDisplayString as _toDisplayString, createVNode as _createVNode, createTextVNode as _createTextVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
const _hoisted_1 = /*#__PURE__*/_createTextVNode(" Hello World! ")
const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "ffff", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "ffffww", -1 /* HOISTED */)
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1,
_createVNode("p", null, _toDisplayString(_ctx.msd), 1 /* TEXT */),
_hoisted_2,
_hoisted_3
]))
}
这样每次render的时候,就不会被多次创建;只在第一次的时候创建。
3.事件侦听缓存
默认情况下,onclick会被认为是动态绑定的,所以每次都会追踪她的变化;但是因为是同一个函数,所以没有追踪变化,直接从缓存起来复用。
开启事件缓存之前:
import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("button", { onClick: _ctx.onclick }, "点击", 8 /* PROPS */, ["onClick"])
]))
}
静态标记 8 代表的:动态属性;
把onclick事件当成动态属性,那么动态属性就会在下一次的渲染时候,发生对比。
开启事件缓存之后:
import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("button", {
onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onclick && _ctx.onclick(...args)))
}, "点击")
]))
}
注意: 我们观擦到没有了静态标志,在vue3中 diff算法只有有静态标志,才会进行追踪。
------------------------------------------------------------------
1. vue3.0 3中创建方式。
vue-cli
webpack
vite
2. 什么是vite?
vite 是vue作者开发的一款意图取代webpack的工具;
-- 其实原理就是:利用es6的import 会发送请求去加载文件的特性,拦截这些请求,做一些预编译,省去webpack冗长的打包时间;
-安装vite;
npm install -g create-vite-app
-利用vite创建项目
create-vite-app projectName
-安装依赖运行项目
cd projectName
npm install
------------------------------------------------
setup() {}
执行时机
注意点;
1.执行时机,setup先于beforeCreate;
beforeCreate data和methods 还没有初始化好;
created data和methods 还没有初始化好;
2. 注意点
在setup 中无法使用data和methods;
vue为了避免错误使用,它直接将setup中的this修改成了undefined;
setup 只能是同步的,不能是异步的。
-------------------------------------------------
reactive。
1.什么是reactive?
是vue3.0中提供响应式数据的方法;
vue2.x中实现响应式数据:object.defineProperty
vue3.0中实现响应式数据:es6中的proxy;
2.reactive注意点。
参数必须是对象;
如果给reactive传递了其他对象,界面不会自动更新;
如果想更新,可以通过重新赋值的方法;
-------------------------------------------------
ref
ref(18) -》 reactive({value:18})
底层的本质就是reactive,但是在vue使用的时候就是age;
在setup中改变的时候就是,age.value;
-------------------------------------------------
ref 和 reactive的区别?
如果使用reactive创建数据,在temple中不会自动添加value;
如果使用的是ref,会自动添加.value;
isRef isReactive 判断当前数据类型 ref reactive
使用方法:
isRef(age)
isReactive(age)
-------------------------------------------------
递归监听:
通过ref reactive创建的数据默认就是递归监听;
非递归监听:
只监听第一层;
shallowReactive
shallowRef 通过这两个创建的就是非递归监听;
1.使用vue2.x实现简单的todolist
实现删除:点击对应的数据,就删除掉此条数据
<template>
<ul>
<li v-for="(stu, index) in stus" :key="stu.id" @click="remStu(index)">
{{index}} -- {{stu.name}} -- {{stu.age}}
</li>
</ul>
</div>
</template>
export default {
name: 'App',
data(){
return {
stus:[
{id:1, name:"zs", age:10},
{id:2, name:"ls", age:20},
{id:3, name:"ww", age:30},
]
}
},
methods:{
remStu(index) {
this.stus = this.stus.filter((stu,idx) => idx!== index);
},
}
}
实现添加todo:
<template>
<div>
<form >
id: <input type="text" v-model="stu.id">
name: <input type="text" v-model="stu.name">
age: <input type="text" v-model="stu.age">
<input type="submit" @click="addStu ">
</form>
<ul>
<li v-for="(stu, index) in stus" :key="stu.id" @click="remStu(index)">
{{index}} -- {{stu.name}} -- {{stu.age}}
</li>
</ul>
</div>
</template>
export default {
name: 'App',
data(){
return {
stu: {
id:'',
name:"",
age:''
},
stus:[
{id:1, name:"zs", age:10},
{id:2, name:"ls", age:20},
{id:3, name:"ww", age:30},
]
}
},
methods:{
remStu(index) {
this.stus = this.stus.filter((stu,idx) => idx!== index);
},
addStu(e) {
e.preventDefault();
const stu = Object.assign({}, this.stu);
this.stus.push(stu);
this.stu.id="";
this.stu.name="";
this.stu.age="";
}
}
}
从中我们可以发现:
vue2.x中的缺点: 新增一个功能,就要在data(){}中新增定义一个数据结构;业务逻辑就要在methods 或computed 或 watch 中添加业务逻辑;维护起来比较麻烦;
vue3.0就很好的解决了这个缺点。
使用vue3实现同样的功能:
<template>
<form action="">
id: <input type="text" v-model="state2.stu.id">
name: <input type="text" v-model="state2.stu.name">
age: <input type="text" v-model="state2.stu.age">
<input type="submit" @click="addStu ">
</form>
<ul>
<li v-for="(stu, index) in state.stus" :key="stu.id" @click="remStu(index)">
{{index}} -- {{stu.name}} -- {{stu.age}}
</li>
</ul>
</template>
import { reactive } from 'vue';
// ref 函数只能监听简单数据结构,不能监听复杂的数据结构(数组/对象);
// reactive 可以;
import userRemoveStudent from './js/removeStu';
import userAddStudent from './js/addStu';
export default {
name: 'App',
// setup函数是组合api的入口函数;
setup() {
// let state = reactive({
// stus:[
// {id:1, name:"zs", age:10},
// {id:2, name:"ls", age:20},
// {id:3, name:"ww", age:30},
// ]
// });
// function remStu(index) {
// state.stus = state.stus.filter((stu, idx) => idx !== index );
// };
// let state2 = reactive({
// stu:{
// id:"",
// name:"",
// age:""
// }
// });
// function addStu(e) {
// e.preventDefault();
// const stu = Object.assign({}, state2.stu);
// state.stus.push(stu);
// state2.stu.id="";
// state2.stu.name="";
// state2.stu.age="";
// }
let { state, remStu, } = userRemoveStudent();
let {state2, addStu, } = userAddStudent(state);
return {
state,
remStu,
state2,
addStu,
}
},
}
import { reactive } from 'vue';
function userRemoveStudent() {
let state = reactive({
stus:[
{id:1, name:"zs", age:10},
{id:2, name:"ls", age:20},
{id:3, name:"ww", age:30},
]
});
function remStu(index) {
state.stus = state.stus.filter((stu, idx) => idx !== index );
};
return {
state,
remStu,
}
}
export default userRemoveStudent;
import { reactive } from 'vue';
export default function userAddStudent(state) {
let state2 = reactive({
stu:{
id:"",
name:"",
age:""
}
});
function addStu(e) {
e.preventDefault();
const stu = Object.assign({}, state2.stu);
state.stus.push(stu);
state2.stu.id="";
state2.stu.name="";
state2.stu.age="";
};
return {
state2,
addStu,
}
}
说明:reactive接受的是一个对象;
ref 接受的是简单的数据类型;
- ref实例:
<template>
<div>
{{ count }}
</div>
<button @click="addCount">加</button>
</template>
<script>
// vue3.0 中使用组合api 进行优化;
import { ref, reactive } from 'vue';
// ref 函数只能监听简单数据结构,不能监听复杂的数据结构(数组/对象);
// reactive 可以监听对象;
export default {
name: 'App',
// setup函数是组合api的入口函数;
setup() {
// 定义一个变量,初始值为0;
// 这个变量发生变化后,vue ui 会自动发生变化;
let count = ref(0);
// 在组合API中,如果想定义方法,不用在methods中定义,直接定义就好;
function addCount () {
console.log(count,'count')
count.value += 1;
};
// 将变量暴露出去;
return {
count,
addCount,
}
}
}
</script>
3.customRef 自定义一个ref
<template>
<div>
<ul>
<li v-for="(item, index) in state" :key="item">
{{index}} -- {{item.name}}--{{item.age}}
</li>
</ul>
</div>
<button @click="myFun">按钮</button>
</template>
<script>
// customRef:自定义一个ref
import {customRef} from 'vue';
function myRef(value) {
return customRef((track, trigger) => {
fetch(value)
.then(res => {
console.log('res1', res);
return res.json();
})
.then(data => {
value = data;
trigger();
})
.catch(err => {
console.log('err', err);
})
return {
get() {
// 注意不能在get方法中进行忘了请求;
// 渲染界面 -》调用get -》 发送网络请求
// 保存数据-》 更新界面-》 调用get;
track(); // 告诉vue 需要被追踪;
return value;
},
set(newValue){
value = newValue;
trigger();// 告诉vue更新界面;
}
}
})
}
export default {
name: 'App',
setup(){
let state = myRef('../public/data.json');
return {
state
}
}
}
</script>