在Vue3.0中,对于编程语法方面最大的亮点应该就是Composition API,可以避免我们在Vue2.x中的碎片化编程的方式,易于后期维护。闲话不多说,我们学习一下Composition API的主要思想和使用,在整个过程中我们会使用鼠标位置显示的小栗子来讲解。
setup
setup是组合式(Composition)编程的入口,setup接受两个值:props 和 context,在这里我们先不讲解;返回一个对象,我们将需要返回的内容放在这个对象中,这样在组件其余部分(比如:计算属性、方法、生命周期钩子等等)都可以访问到。
setup在组件创建之前执行,也就是说在setup千万不要调用this,因为是undefined,同样也不要访问data property、computed property 或 methods,因为也是访问不到滴。
<body>
<div id="app">
X: {{position.x}} <br/>
y: {{position.y}}
</div>
<script type="module">
import {createApp} from './node_modules/vue/dist/vue.esm-browser.js'
createApp( {
setup() {
let position = {
x: 0,
y: 0
}
return {
position
}
},
mounted() {
console.log(this.position)
this.position.x = 100
}
}).mount("#app");
</script>
</body>
reactive
在上述例子中,position不是响应式的数据,所以在mounted中,我们改变其值,页面不会变化,可以通过reactive使数据变为响应式数据。
let position = reactive({
x: 0,
y: 0
})
生命周期函数
虽然vue有声明周期函数,但是因为我们将来要把一个功能抽离到一个函数中,所有在setup中要用到声明周期函数。在setup中使用生命周期函数的话,需要前面加on,并且首字母大写。在上面的例子中,我们在onMounted中监听鼠标滑动事件,在onUnmounted函数中去除鼠标监听事件。
const updataMousePosition = (e)=>{
position.x = e.pageX
position.y = e.pageY
};
onMounted(()=> {
window.addEventListener("mousemove",updataMousePosition)
})
onUnmounted(()=> {
window.removeEventListener("mousemove",updataMousePosition)
})
提取函数
Composition API 的核心思想就是将不同的功能封装到不同的函数中,因此我们将上边获取鼠标移动位置,封装成一个函数。
function getMousePosition() {
let position = reactive({
x: 0,
y: 0
})
const updataMousePosition = (e)=>{
position.x = e.pageX
position.y = e.pageY
};
onMounted(()=> {
window.addEventListener("mousemove",updataMousePosition)
})
onUnmounted(()=> {
window.removeEventListener("mousemove",updataMousePosition)
})
return position;
}
setup() {
let position = getMousePosition()
return {
position
}
},
toRefs
toRefs 会将响应式对象的属性,变成相应式的,方便我们结构某个响应式对象,传递给toRefs函数的参数必须是代理对象,不然会警告。
function getMousePosition() {
let position = reactive({
x: 0,
y: 0
})
......
return toRefs(position);
}
setup() {
let {x,y} = getMousePosition()
return {
x, y
}
},
reactive 和 ref
reactive 是将引入类型的数据变成响应式数据;而ref是将基本类型的数据转化为响应式数据。
<body>
<div id="app">
<button @click="increase">+</button>
<span>{{count}}</span>
</div>
<script type="module">
import {ref, createApp} from './node_modules/vue/dist/vue.esm-browser.js'
function useCount() {
let count = ref(0)
return {
count,
increase:()=> {
count.value += 1;
}
}
}
createApp({
setup() {
return {
...useCount()
}
}
}).mount("#app")
</script>
</body>
computed
当对一个响应式数据做某种处理后,展示可以使用computed,computed有两种使用方法:
- 接受一个getter函数,返回一个不变的响应式对象
- 使用具有 get 和 set 函数的对象
在这里演示第一种用法
createApp({
setup() {
let todo = reactive(todos)
let noComputedCount = computed(()=> todo.filter(item=>!item.isCompleted).length)
console.log(noComputedCount)
return {
noComputedCount,
plus:()=>{
todo.push({
item:"吃饭",
isCompleted: false
})
}
}
}
}).mount("#app")
watch 监听数据的变化
在vue3.0中watch的使用和Vue2.0基本一致,在传参时有个变化,在vue2.x中,第一个参数是字符串,而在vue3.0中是要监听的响应式对象。
<body>
<div id="app">
<div>请输入问题:<input type="text" v-model="question"></div>
<div>答案:{{answer}}</div>
</div>
<script type="module">
import {createApp, watch, ref} from './node_modules/vue/dist/vue.esm-browser.js'
import debounce from './node_modules/lodash-es/debounce.js'
createApp({
setup() {
let question = ref("")
let answer = ref("")
const getData = async () => {
let data = await fetch('https://www.yesno.wtf/api')
answer.value = data.statusText
}
watch(question,debounce(getData, 300))
return {
question,
answer
}
}
}).mount("#app");
</script>
</body>
watchEffect
watchEffect的作用和watch一致,只不过在语法上有点不一样,watchEffect接收一个函数,在函数内的响应式对象有变化时,这个函数就会被执行一次。watchEffect返回暂停函数,当这个函数被调用后,watchEffect就不起作用了。
<body>
<script type="module">
import {createApp, watchEffect, ref} from './node_modules/vue/dist/vue.esm-browser.js'
createApp({
setup() {
let count = ref(0)
let stop = watchEffect(()=>{
console.log(count.value)
})
return {
count,
stop,
increase:()=>{
count.value += 1;
}
}
}
}).mount("#app")
</script>
</body>