vue3.0与2.0的不同
Vue3.0 和 Vue2.0 相比,优势主要体现在:更快、更小、更易维护、更易于原生、让开发者更爽;
更快
- virtual DOM 完全重写,mounting & patching 提速 100%;
- 更多编译时 (compile-time)提醒以减少 runtime 开销;
- 基于 Proxy 观察者机制以满足全语言覆盖以及更好的性能;
- 放弃 Object.defineProperty ,使用更快的原生 Proxy
- 组件实例初始化速度提高 100%;(速度翻倍)
- 提速一倍/内存使用降低一半;(内存减半)
更易维护
- 3.0 新加入了 TypeScript 以及 PWA 的支持和部分命令发生了变化:
- 下载安装 npm install -g vue@cli
- 删除了vue list
- 创建项目 vue create
- 启动项目 npm run serve
- 默认项目目录结构也发生了变化:
- 移除了配置文件目录,config 和 build 文件夹
- 移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中
- 在 src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件
更小
- Tree-shaking 更友好;
- 新的 core runtime:~ 10kb gzipped;
更易于原声
PWA全称Progressive Web App,即渐进式WEB应用。一个 PWA 应用首先是一个网页, 可以通过 Web 技术编写出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的安装和离线等功能,PWA可以将app的快捷方式放置到桌面上,全屏运行,与原生app无异
3.0的新增方法和新的写法
setup的作用
对比vue2.0的使用方式,你需要把data, method, computed, watch以及生命周期都放到setup函数中来使用
1、setup中的data如何使用?
import { ref, toRefs, reactive } from 'vue'
export default {
name: 'Test',
setup(){
// 在setup中定义template模板使用的响应式变量,你得用ref或者reactive来定义
// 这里的ref你可以理解成一个工厂类,传入的参数就是初始化的变量的值,跟组件的ref概念不能混淆
// 定义单个变量,为了让大家明白意义,我跟vue2.0都进行下对比
// vue2.0,不管定义单个或者多个我们都是定义 在data里,如:
/*
data(){
return {
name: 'zhangmin'
}
}
*/
// 在vue3.0中,如果你只需要定义一个响应式变量,那么你可以用以下ref
// 可能你会疑惑既然是定义变量为什么不用let,var,而用const定义常量的,这里是因为你定义的是一个引用,name指向的永远是一个固定不变的指针地址
const name = ref('zhangmin')
// 注意点,这里要获取name的值怎么获取,通过定义的变量的 .value
console.log('拿到name的值:', name.value)
// 检测某个值是不是响应式的可以用isRef
// 每次都用.value去拿值的写法,是不是有点不适应,而且定义的变量多了我们也不可能定义一堆ref,看起来都丑
// reactive 可以创建一个响应式数据,参数是一个对象
const data = reactive({
name: '我叫张敏君',
sex: '性别很重要',
arr: []
})
// 但是以上还是有个缺点,如果你在return里直接放上data,
//那你使用的时候每次都要data.name,data.sex也麻烦,<div>{{data.sex}}</div>
// 你说你可以解构在return {...data} 如果你这样的,里面的数据都会变成非响应式的,
//vue3.0提供了一个满足你幻想的方法toRefs,使用了这个包装下,你就可以在return里使用解构了
// 包装上面的data
const refData = toRefs(data)
// 在data中都有个return ,这里当然也必须要有的,但是这里是所有方法计算属性都要通过这个返回
// 有人疑惑,那我可以直接在这个return上定义变量吗,答案是可以,但是定义的变量不是响应式的,不可变化
return {
...refData, // 你也可以直接在这里用...toRefs(data) 这样会简单点
name,
rules: [] //如果你有什么不会变化的数据,如规则啊,配置啊,可以直接在这定义而不需要通过ref和reactive
}
}
}
2.setup中的method如何使用?
import { ref } from 'vue'
export default {
name: 'Test',
setup(){
// 定义一个响应式数据
const baby = ref('1岁boby')
// 定义method,把方法名字在return里返回
// 注意:这里用调用响应式的数据也就是您定义的vue2.0的data,
//不可以用this,这个setup函数在01里已经说明过了,这个时候相当于vue2.0的beforeCreate和created,
//这里一开始就会运行,还没有this的指向,是个undefined,访问所有你定义的响应式的变量都要.value去访问
const wantToKnowBabysName = () => {
console.log("oh,he is a " + baby.value)
}
const getData = () => {}
// 对比vue2.0
/*
method: {
wantToKnowBabysName(){
console.log("oh,he is a " + baby.value)
},
getData() {
}
}
*/
return {
baby,
wantToKnowBabysName,
getData
}
}
}
3、setup中的computed如何使用?
// 注意使用的时候引入computed
import { ref, computed} from 'vue'
export default {
name: 'Test',
setup(){
// 定义一个响应式数据
const baby = ref('嘎嘎嘎')
// 定义翠花年龄
const age = ref(28)
// computed计算属性传入一个回调函数
const areYouSureYouAreABaby = computed(() => {
return `I'm sure,I'm a 300 month baby, ${baby.value}`
})
// set和get方式
const setAge= computed({
get() {
return age.value + 10
},
set(v) {
age.value = v - 10
}
})
// 对比vue2.0
/*
computed: {
areYouSureYouAreABaby (){
return `I'm sure,I'm a 300 month baby, ${baby.value}`
},
setAge:{
get(){
return age + 10
},
set(v) {
age = v - 10
}
}
}
*/
return {
baby,
age,
areYouSureYouAreABaby
}
}
}
4、setup中的watch如何使用?
// 注意使用的时候引入watch
import { ref, watch, watchEffect } from 'vue'
export default {
name: 'Test',
setup(){
// 定义一个响应式数据
const baby = ref('嘎嘎嘎')
const arr = ref(['翠花', '小红'])
// 监听一个值的情况,有两种方式
// watch 有三个参数:第一个是个getter(所谓getter写法就是你要写个getter函数),第二个是个回调函数,第三个是个options(这个参数是放vue2.0的deep或者immediate等可选项)
// 第一种:直接放ref
watch(baby, () => {
return `I'm sure,I'm a 300 month baby, ${baby.value}`
})
// 第二种:放ref的value值
watch(() => baby.value, () => {
return `I'm sure,I'm a 300 month baby, ${baby.value}`
})
// 监听多个值的时候 ,第一个参数是个数组,里面放监听的元素
watch([baby,arr], (v, o) => {
// 这里的v,o也是数组,所以你取值的时候v[0],v[1]拿到第几个元素的变化
...
}, {
deep: true,
immediate: true
})
// 或者写成
watch([baby,arr], ([baby, arr], [prebaby,prearr]) => {
...
})
// 对比vue2.0
/*
watch: {
baby(v, o) {
},
arr: {
handle(v,o) {},
deep: true,
immediate: true,
flush: 'pre' // 这个默认有三个参数,'pre'| 'post' | 'sync',默认‘pre’组件更新前运行,'post'组件渲染完毕后执行,一般用于你需要去访问$ref的时候可以用这个,'sync'是一旦你的值改变你需要同步执行回调的时候用这个
}
}
*/
// watch的写法跟vue2的$watch写法一样,可以参考
// vue3.0 watchEffect 用法
// watchEffect 有两个参数,一个是副作用函数(就是外部的数据对这个函数产生影响的,通俗点说就是在这个函数内部使用了外面的变量等),一个是options()
// 在vue2.0中,我们一般在created里添加一些监听事件,比如你的$bus的一些事件监听,在setup中就可以在这个里面写
watchEffect((onInvalidate) => {
// 这里的变化就相当于依赖了age.value,如果age变化了就会触发这个监听
// 刚刚创建组件的时候会立即执行这个
const _age= `her age is ${age.value}`
console.log(_age)
//有时候你需要在这里挂载一些监听事件
const handerClick = ()=>{}
document.addEventlistener('click', handerClick)
// 在vue2.0我们需要在destroy的时候remove它,这里提供了一个方法onInvalidate回调解决remove的问题
onInvalidate(()=>{
/*
执行时机: 在副作用即将重新执行时,就是在每次执行这个watchEffect回调的时候会先执行这个,如果在setup()或生命周期钩子函数中使用watchEffect, 则在卸载组件时执行此函数。
*/
document.removeEventListener('click',handerClick )
})
})
// 这个也是支持async,await的
const data = ref(null)
watchEffect(async onInvalidate => {
// 假设个接口获取数据的
data.value = await fetchData()
onInvalidate(() => {...})
})
// 再来理解options:这里有三个参数flush,onTrigger,onTrack
watchEffect(onInvalidate => {
onInvalidate(() => {...})
}, {
flush: 'pre' // 跟watch一样,默认pre,组件更新前去调用
onTrigger(e) {
// 依赖项变化时候触发这个即依赖项的set触发的时候
},
onTrack(e) {
// 依赖项被调用的时候触发这个即依赖项的get触发的时候
}
})
return {
baby,
areYouSureYouAreABaby,
data
}
}
}
5、setup中的生命周期如何使用?
//这里注意引入组件,用什么引入什么
import {onBeforeMount
,onMounted
,onBeforeUpdate
,onUpdated
,onBeforeUnmount
,onUnmounted} from 'vue';
export default {
setup: function () {
//组件挂载之前
onBeforeMount(() =>{
console.log("onBeforeMount");
});
//组件挂载完成
onMounted (() => {
console.log("onMounted");
});
//数据更新,虚拟 DOM 打补丁之前
onBeforeUpdate (() => {
//注意,onBeforeUpdate 和 onUpdated 里面不要修改值,会死循环的哦!
console.log("onBeforeUpdate");
});
//数据更新,虚拟 DOM 渲染完成
onUpdated (() => {
console.log("onUpdated");
});
//组件销毁之前
onBeforeUnmount (() => {
console.log("onBeforeUnmount");
});
//组件销毁后
onUnmounted (() => {
console.log("onUnmounted");
});
}
}
vue3.0各个属性的介绍
reactive 与 ref
reactive用于为对象添加响应式状态。接收一个js对象作为参数,返回一个具有响应式状态的副本。
ref 用于为数据添加响应式状态。由于reactive只能传入对象类型的参数,而对于基本数据类型要添加响应式状态就只能用ref了,同样返回一个具有响应式状态的副本,获取数据值的时候需要加.value。可以理解为ref是通过reactive包装了一层具有value属性的对象实现的 参数可以传递任意数据类型,传递对象类型时也能保持深度响应式,所以适用性更广。 vue 3.0 setup里定义数据时推荐优先使用ref,方便逻辑拆分和业务解耦
代码如下:
<template>
<div> Count is: {{ state.count }}</div>
<div> name is: {{ name }}</div>
<div> num is: {{ num.count }}</div>
</template>
<script>
import { reactive,ref} from "vue"
export default {
setup() {
const state = reactive({
count: 0,
});
// 为基本数据类型添加响应式状态
const name = ref("Neo");
// 为复杂数据类型添加响应式状态
const num = ref({
count: 0,
});
return {
state,name,num
}
}
}
</script>
这时我们也可以实现一个简单的增加,再次引入一个vue的计算属性 computed,computed一定要import引入,如果不引入的话 他会报错,computed不存在
代码如下
<template>
<div> Count is: {{ state.count }} double:{{state.double}}</div>
</template>
<script>
import { reactive,computed} from "vue"
export default {
setup(){
const state = reactive({
count: 0,
double: computed(() => state.count * 2),
});
return {
state
}
}
}
</script>