Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
作用: 聚合代码 & 逻辑重用
项目目录
node_modules // 所有的项目依赖包都放在这个目录下
public // 公共文件夹
favicon.ico // 网站的显示图标
index.html // 入口的html文件
src // 源文件目录,编写的代码基本都在这个目录下
assets // 放置静态文件的目录,比如logo.pn就放在这里
components // Vue的组件文件,自定义的组件都会放到这
App.vue // 根组件,这个在Vue2中也有
main.ts // 入口文件,因为采用了TypeScript所以是ts结尾
shims-vue.d.ts // 类文件(也叫定义文件),因为.vue结尾的文件在ts中不认可,所以要有定义文件
.gitignore // 用来配置那些文件不归git管理
package.json // 命令配置和包管理文件
README.md // 项目的说明文件,使用markdown语法进行编写
tsconfig.json // 关于TypoScript的配置文件
yarn.lock // 使用yarn后自动生成的文件,由Yarn管理,安装yarn包时的重要信息存储到yarn.lock文件中
1. 使用 reactive 绑定数据
<template>
<div>
<h1>使用 reactive 绑定数据</h1>
<p>{{state.msg}}</p>
<p>{{info}}</p>
<p>
<button @click="changeMsg">changeMsg</button>
</p>
</div>
</template>
<script>
// Hooks 编程,在 vue 中导入对应的函数方法,面向函数式进行编程
// Vue-composition-API 这里就是Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
import { defineComponent, reactive } from "vue";
export default defineComponent({
name: 'test1',
setup() { // setup钩子函数
// 使用响应式函数reactive构建proxy响应式对象state
const state = reactive({
msg: '时光'
})
console.log(state); // state对象是一个proxy拦截对象
let info = 'hello'; // info是一个普通对象,修改后不会被proxy拦截,进而页面也不会动态更新
const changeMsg = () => { // 在外边定义methods
state.msg = '时光,你好'
info = 'hello,你好'
}
return { // 使用时,要把对象return出去,才能在template中使用
state,
info,
changeMsg
}
}
})
</script>
2. setup()函数 完成父子通信
1. setup(props)第一个参数props
setup函数接收props作为其第一个参数,props对象是响应式的(单向的父—>子),watchEffect或watch会观察和响应props的更新。不要对props对象进行解构,那样会失去响应性。在开发过程中,props对象对用户空间代码时不可变的,用户尝试修改props时会触发警告
案例1:props作为setup的第一个参数
// 父组件 Home.vue
<template>
<div class="home">
<About :name="sendData"/>
</div>
</template>
<script>
import {ref} from 'vue';
import About from './About'
export default{
components:{
About,
},
setup(){
const sendData = ref('这世界很酷');
return {
sendData
}
}
}
</script>
// 子组件About.vue
<template>
<div class="about">
{{propContent}}
</div>
</template>
<script>
import {watchEffect} from 'vue';
export default{
props:{
name:String
},
setup(props){
let propContent= props.name;
// watchEffect(()=>{
// propContent = props.name
//})
return {
propContent
}
}
}
</script>
2. setup(props,context)第二个参数Context上下文对象
// 父组件 Home.vue
<template>
<div class="home">
<About :name="sendData.val" @name-changed=changeName>
世界变化不停,人潮川流不息
</About>
</div>
</template>
<script>
import {reactive} from 'vue';
import About from './About';
export default{
components:{
About,
},
setup(){
const sendData = reactive({
val:'sendData'
})
setTimeout(()=>{
sendData.val+=1;
},1000)
function changeName(msg){
console.log(`子组件传递了${msg}过来`)
}
return {
sendData,
changeName,
}
}
}
</script>
//子组件 About.vue
<template>
<div class="about">
<button @click="fn">子改父</button>
</div>
</template>
<script>
import {watch} from 'vue';
export default {
props:{
name:String
},
setup(props, context) {
console.log(context,"上下文");
let num=100;
let fn=()=>{
content.emit('name-changed',num)//相当于this.$emit()
}
return {
fn
}
);
},
}
</script>
3. 使用 ref、toRefs 绑定数据
<template>
<div>
<p>使用v-model双向数据绑定的数据内容是:{{ msg }}</p>
<p>
<!-- 自己实现双向数据绑定,监听input事件,动态修改nmsg的值 -->
<input type="text" ref="myInput" @input="input" :value="nmsg" />
</p>
<p>使用@input事件动态实现双向数据绑定的数据内容是:{{ nmsg }}</p>
<p>
<!-- 使用ref方法动态定义并双向绑定hmsg -->
<input type="text" v-model="hmsg" @input="hmagInpu" />
</p>
<p>使用ref方法动态定义并双向数据绑定的数据hmsg是:{{ hmsg }}</p>
<p>toRefs 来实现在模板中不需要追加 state 调用数据:{{ msg }}</p>
</div>
</template>
<script>
import {
defineComponent,
reactive,
getCurrentInstance,
toRefs,
ref,
computed,
} from "vue";
export default defineComponent({
setup() {
const state = reactive({
msg: "",
nmsg: "",
cmsg: computed(() => {
// 1.计算属性
return state.msg.length;
}),
});
// 2.可以使用getCurrentInstance hook 来拿到当前实例化对象上下文信息,但是除非极其特殊的情况,否则不建议这样使用
const { ctx } = getCurrentInstance();
const input = () => {
// 在vue3中,因为是面向hooks函数编程,所以,无法通过this拿到当前vue实例化对象
console.log(ctx.$refs.myInput.value); // 像使用vue2中的this一样,使用ctx(上下文内容信息)
state.nmsg = ctx.$refs.myInput.value;
};
// 3.使用ref方法来定义一个响应式监听的对象,在实际开发中我们都是用这种方法来构建响应式对象
const hmsg = ref("abc");
const hmagInpu = () => {
// 在内部使用hmsg的值,需要使用value来获取对应的值
console.log("获取到的hmsg值是:" + hmsg.value);
};
return {
// 4.使用toRefs hook方法方便,访问msg不需要使用state.msg,直接msg就可以获取到
...toRefs(state),
hmsg,
input,
hmagInpu,
};
},
});
</script>
4. watch、watchEffect 数据监听
<template>
<div>
<h1>watch、watchEffect 数据监听</h1>
<p>{{ msg }}</p>
<p>{{ msg2 }}</p>
<p>{{ info }}</p>
<p>
<button @click="changeMsg">changeMsg</button>
</p>
<p>
<button @click="changeMsg2">changeMsg2</button>
</p>
</div>
</template>
<script>
import { defineComponent, reactive, watchEffect, watch, toRefs } from "vue";
export default defineComponent({
name: "watch",
// setup钩子函数
setup() {
// 使用响应式函数reactive构建proxy响应式对象state
const state = reactive({
msg: "时光",
msg2: "kity",
changeMsg2: () => {
state.msg2 = "kity,你好";
},
});
const changeMsg = () => {
// 在外边定义methods
state.msg = "时光,改变";
info = "hello,改变";
};
let info = "hello";
// watch监听只能是 getter/effect 函数、ref、reactive对象或数组
// 简单监听
watch(state, () => {
console.log("观察整个state中属性变化", state.msg); // 只要state中的值有变化,就会打印
});
// 监听指定的信息
watch(
() => state.msg,
(newVal, oldVal) => {
console.log("01-msg的新值是:" + newVal + "-------旧值是:" + oldVal);
}
);
// 监听多个属性(数组形式)
watch([() => state.msg, () => state.msg2], (newVal, oldVal) => {
console.log("02-msg的新值是:" + newVal + "-------旧值是:" + oldVal); // 02-msg的新值是:时光,你好,俞亮-------旧值是:时光,俞亮
});
// 不需要指定监听的属性
watchEffect(() => {
// 程序运行时,初始化就会执行一次,完成监听准备工作
console.log("03-watchEffect监听 state 中数据变化:", state.msg); // 有点像computed计算属性,用到的数据发生改变才会执行
});
// 使用时,要把对象return出去,才能在template中使用
return {
...toRefs(state),
info,
changeMsg,
};
},
});
</script>
5. 生命周期
setup中没有this ,使用生命周期时需要导入
setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
onBeforeMount() : 组件挂载到节点上之前执行的函数。
onMounted() : 组件挂载完成后执行的函数。
onBeforeUpdate(): 组件更新之前执行的函数。
onUpdated(): 组件更新完成之后执行的函数。
onBeforeUnmount(): 组件卸载之前执行的函数。
onUnmounted(): 组件卸载完成后执行的函数
// 若组件被<keep-alive>包含,则多出下面两个钩子函数。
onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
vue2与vue3生命周期的区别
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
除了这些钩子函数外,Vue3.x还增加了onRenderTracked和onRenderTriggered函数
这两个钩子函数是Vue3.x版本新加的两个钩子函数,官方说是用来调试使用的,但是目前还没有给出具体的调试案例
onRenderTracked
// onRenderTracked,
// 它会跟踪页面上所有响应式变量和方法的状态,也就是我们用return返回去的值,他都会跟踪
import { .... ,onRenderTracked,} from "vue";
onRenderTracked((event) => {
console.log("状态跟踪组件----------->");
console.log(event);
});
onRenderTriggered
// onRenderTriggered,它不会跟踪每一个值,而是给你变化值的信息,并且新值和旧值都会给你明确的展示出来。
import { .... ,onRenderTriggered,} from "vue";
onRenderTriggered((event) => {
console.log("状态触发组件--------------->");
console.log(event);
});