本节源码立即前往
前段时间尤大在哔哩哔哩直播了vue3的预览,来简单实践一下吧
api文档 Composition API RFC 立即前往
vue3地址立即前往
vue3的改变
克隆一个官方仓库
git clone https://github.com/vuejs/vue-next.git
打开这个项目,下载一下依赖,然后编译
npm i
npm run dev
编译文件在vue-next\packages\vue\dist
,可以把它复制出来放到我们创建的项目文件夹
在vue-next\packages\vue\examples
目录下有官方的示例
首先确保你的@vue/cli为最新版本 vue -V
然后使用 vue create vue3demo
创建一个vue项目,创建的时候勾选 vuex router
然后进入项目文件夹,命令行安装插件vue add vue-next
将项目升级到vue3,打开package.json可以发现都升级到了最新版本
为了体验整个api的变化,我们先使用直接引入的方式体验效果,新建一个index.html 引入vue.global.js
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="./js/vue.global.js">script>
head>
<body>
body>
html>
然后我们新建一个盒子用来挂载vue实例,新建一个模板当做根节点
<body>
<div id='app'>
div>
<template id="root">
<div>
div>
template>
body>
实例化一个vue3,vue3是按需引入,使用一个api之前需要先引入,通过createApp
来实例化
<script>
const {
createApp
} = Vue;
const root = {
template: '#root',
}
createApp(root).mount('#app');
</script>
setup
函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。
vue3将更多的方法和数据在 setup
函数中定义,这就是大家都觉得像react hook 的原因,其实实现的原理是不同的,只是写法有点像;这样做的目的就是为了更好的实现逻辑复用,具体会在后面举例
与 2.x 版本生命周期相对应的组合式 API
beforeCreate
-> 使用 setup()
created
-> 使用 setup()
beforeMount
-> onBeforeMount
mounted
-> onMounted
beforeUpdate
-> onBeforeUpdate
updated
-> onUpdated
beforeDestroy
-> onBeforeUnmount
destroyed
-> onUnmounted
errorCaptured
-> onErrorCaptured
setup
最后返回所有的对象和方法,注意这里的msg
不是响应式对象
const root = {
template: '#root',
// beforeCreate created data和methods
setup() {
console.log('vue init');
const msg = "vue init";
return {
msg
};
},
}
<template id="root">
<div>
{{msg}}
div>
template>
ref
和reactive
都是用来创建响应式对象的,接下来的案例都使用脚手架创建项目来进行测试
打开views/Home.vue
文件,删除掉无用的东西,首先引入ref
, reactive
import { ref, reactive } from "vue";
export default {
name: "Home",
setup() {
// 定义一个ref响应式对象
const count = ref(0);
// 如果要定义多个可以使用reactive
const state = reactive({
size: 36,
color: "red"
});
// 定义一个方法
const increment = () => {
count.value++;
};
return {
count,
increment,
state
};
}
};
在页面中的使用和vue2是一样的
{{count}}
reactive
上面reactive
的导出和使用,必须state.key
,如果想像vue2中的data一样定义直接使用,可以使用 toRefs
引入 import { ref, reactive, toRefs } from "vue";
,使用 toRefs
返回展开对象,如果你不使用toRefs
而直接返回对象,原对象的响应式将丢失。
return {
count,
increment,
...toRefs(state)
};
页面中使用
reactive
我们来到about.vue
中进行代码编写,首先引入需要使用的
import { reactive, watch, computed, toRefs, watchEffect } from "vue";
watchEffect
传入一个函数并立即执行,如果函数里面使用了上面定义好的响应式对象,当对象发生变化时,会再次触发这个函数
定义计算属性和监听器
export default {
setup() {
const state = reactive({
num1: 1,
//定义一个计算属性
num2: computed(() => state.num1 * 2)
});
// 如果响应性的属性有变更,就会触发这个函数,但他是惰性的
watchEffect(() => {
console.log(`effect 触发了!${state.num1}`);
});
// 定义一个监听器
const stop = watch(state, (val, oldVal) => {
console.log("watch ", oldVal.num1);
});
//数值增加方法
const increment = () => state.num1++;
// 停止监听
const stopwatch = () => stop();
return {
...toRefs(state),
stopwatch,
increment
};
}
};
查看效果
在components
文件夹下新建一个DomRef.vue
文件,定义一个空的ref
响应数据refdemo
并返回,页面中使用ref
标签来绑定这个数据,然后就可以通过操作这个响应数据来操作dom
domref
在home
组件中使用这个组件查看效果
<DomRef></DomRef>
...
import DomRef from "../components/DomRef";
...
components: {
HelloWorld,
DomRef,
},
看看效果
和vue2的通信大同小异,新建ComDemo.vue
,setup
函数接受一个 props
和 context
上下文
{{name}}
来的Home.vue
中使用这个组件,并给这个子组件绑定一个响应式的ref
属性
<ComDemo :name="'我是父组件传值'" @talk="talk" ref="comdemo"></ComDemo>
import ComDemo from "../components/ComDemo";
...
components: {
HelloWorld,
DomRef,
},
...
setup() {
// 定义一个ref响应式对象
const comdemo = ref(null);
onMounted(() => {
//得到子组件的值
console.log(comdemo.value.str);
// 触发子组件事件
comdemo.value.talk();
});
return {
...
comdemo
};
}
看看效果
绑定一个方法给子组件
...
setup() {
const talk = e => {
console.log(e);
};
...
return {
...
talk,
comdemo
};
...
ComDemo.vue
setup(props, context) {
...
// setup中触发父组件事件
context.emit("talk", "我是子组件 我触发你了");
...
return {
str,
talk
};
}
效果
这个和vue2使用一样
父组件定义
import { provide } from "vue";
...
provide("injectmsg", "provide talk");
后代组件使用
import { inject } from "vue";
...
const injectmsg = inject("injectmsg");
console.log("injectmsg :>> ", injectmsg);
前面说到 Composition API
的好处,这来举一个例
放一个尤大神的demo,这是一段鼠标操作的功能代码,我们自己还需要编写一个功能来实现结合
const useMouse = () => {
const state = reactive({
x: 0,
y: 0
});
const update = e => {
state.x = e.pageX;
state.y = e.pageY;
};
onMounted(() => {
window.addEventListener("mousemove", update);
});
onUnmounted(() => {
window.removeEventListener("mousemove", update);
});
return toRefs(state);
};
我们再写一个键盘方法,记录每次用户按下键盘
// 监控键盘事件
const useKeyBoard = () => {
const status = ref(false);
const update = () => {
status.value = !status.value;
};
onMounted(() => {
window.addEventListener("keypress", update);
});
onUnmounted(() => {
window.removeEventListener("onkeydown", update);
});
return {
status
};
};
我们来到 HelloWorld.vue
组件中使用这两个方法
{{status?`${x}-${y}`:`${y}-${x}`}}
我们在页面中显示鼠标方位,当我们按下任何按键的时候,这个显示颠倒
看下效果
vuex
和vuerouter
vuex
和vuerouter
在实例化方式上有了一点区别,分别使用 createStore
和createRouter
进行实例化
vuex
打开vue3demo\src\store\index.js
文件
import Vuex from 'vuex'
export default Vuex.createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
console.log('当前count:',state.count);
}
},
actions: {},
modules: {}
});
新建一个 RouterAndVuex.vue
组件
看看效果
vuerouter
看看效果