文章内容输出来源 拉勾教育大前端高薪训练营
本文主要围绕 Composition API
来讲解如何使用,分别是以下几个API 函数, 通过学习,可以让你可以更快上手 Composition API
,掌握 Vue.js 3.0
的新特性。
- 生命周期钩子变化
- reactive API
- toRefs API
- ref API
- computed API变化
- watch API变化
- toRefs 原理
- watchEffect API
1、Compostion API
安装Vue3.0 ,体验 createApp 的使用
npm install vue@3.0.0-rc.1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
x: {{ position.x }}
y: {{ position.y }}
</div>
<script type="module">
import { createApp } from './node_modules/vue/dist/vue.esm-browser.js'
const app = createApp({
data () {
return {
position: {
x: 0,
y: 0
}
}
}
})
console.log(app)
app.mount('#app')
</script>
</body>
</html>
Vue 3.0
和 Vue2.0
的区别,成员要少很多,没有$开头, 使用方式和以前一样
2、生命周期钩子函数
setUp 函数
import { createApp, reactive, onMounted, onUnmounted } from './node_modules/vue/dist/vue.esm-browser.js'
const app = createApp({
setup () {
// 第一个参数 props
// 第二个参数 context, attrs, emit, slots
const position = reactive({
x: 0,
y: 0
})
const update = e => {
position.x = e.pageX;
position.y = e.pageY;
}
onMounted (() => {
window.addEventListener('mousemove', update)
})
onUnmounted (() => {
window.removeEventListener('mousemove', update)
})
return {
position
}
}
})
console.log(app)
app.mount('#app')
当鼠标移动的时候显示鼠标移动的位置,当组件卸载时,鼠标移动的事件也要移除
将获取鼠标位置的方法封装到一个函数中,优化代码
import { createApp, reactive, onMounted, onUnmounted } from './node_modules/vue/dist/vue.esm-browser.js'
function useMousePosition () {
// 第一个参数 props
// 第二个参数 context, attrs, emit, slots
const position = reactive({
x: 0,
y: 0
})
const update = e => {
position.x = e.pageX;
position.y = e.pageY;
}
onMounted (() => {
window.addEventListener('mousemove', update)
})
onUnmounted (() => {
window.removeEventListener('mousemove', update)
})
return position
}
const app = createApp({
setup () {
const position = useMousePosition()
return {
position
}
}
})
console.log(app)
app.mount('#app')
3、reactive、toRefs 、ref 函数
都是创建响应式数据的
先看上一节出现的小问题
import { createApp, reactive, onMounted, onUnmounted } from './node_modules/vue/dist/vue.esm-browser.js'
function useMousePosition () {
// 第一个参数 props
// 第二个参数 context, attrs, emit, slots
const position = reactive({
x: 0,
y: 0
})
const update = e => {
position.x = e.pageX;
position.y = e.pageY;
}
onMounted (() => {
window.addEventListener('mousemove', update)
})
onUnmounted (() => {
window.removeEventListener('mousemove', update)
})
return position
}
const app = createApp({
setup () {
// const position = useMousePosition()
const { x, y} = useMousePosition()
return {
x,
y
}
}
})
console.log(app)
app.mount('#app')
对useMousePosition
进行解构后,数据不是响应式的了
这里的 position
是响应式对象,因为在useMousePosition
中调用了reactive
函数,把传入的对象包装成了 Proxy
对象,也就是说 position
就是 proxy
对象,当 position
访问 x, y的时候会调用代理中的 getter
拦截收集依赖,变化的时候会调用 setter
使用 toRefs
import { createApp, reactive, onMounted, onUnmounted, toRefs } from './node_modules/vue/dist/vue.esm-browser.js'
...
return toRefs(position)
toRefs原理
toRefs 要求传入的参数 必须为代理对象,当前的 position
就是 reactive
返回的代理对象,如果不是的话,会发出警告,提示传递代理对象,
内部会创建一个新的对象,然后遍历传入代理对象的所有属性,把所有属性的值都转换成响应式对象,相当于将postion
的x, y
属性转换成响应式对象,
挂在到新创建的对象上,最后把新创建的对象返回。内部为代理对象的每一个属性创建一个具有 value 属性,value属性具有 getter,setter
, getter
中返回对象属性的值,
setter中给代理对象赋值。所以返回的每一个属性都是响应式的
ref 把普通数据转转换成响应式数据,ref 可以把基本类型包装成响应式数据
<div id="app">
<button @click="increase">点击</button>
<span>{{ count }}</span>
</div>
<script type="module">
import { createApp, ref } from './node_modules/vue/dist/vue.esm-browser.js'
function useCount () {
const count = ref(0)
return {
count,
increase: () => {
count.value++
}
}
}
createApp({
setup() {
return {
...useCount()
}
}
}).mount('#app')
</script>
4、Computed
第一种用法
- wacth(() => { count.value + 1})
第二种用法
const count = ref(1)
const plusOne = computed({
get: () => {
count.value + 1
},
set: val => {
conut.value = val - 1
}
})
<div id="app">
<button @click="push">点击</button>
未完成 {{ activeCount }}
</div>
<script type="module">
import { createApp, reactive, computed } from './node_modules/vue/dist/vue.esm-browser.js'
const data = [
{
text: '看书',
completed: false
},
{
text: '敲代码',
completed: false
},
{
text: '学习',
completed: false
}
]
createApp({
setup() {
const todos = reactive(data)
const activeCount = computed(() => {
return todos.filter(item => !item.completed).length
})
return {
activeCount,
push: () => {
todos.push({
text: '开会',
completed: false
})
}
}
}
}).mount('#app')
</script>
5、Watch
Watch 的三个参数
- 第一个参数: 要监听的数据
- 第二个参数: 监听到数据变化后执行的函数,这个函数有两个参数分别是新值和旧值
- 第三个参数: 选项对象, deep 和 immediate
Watch 的返回值 - 取消监听的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
请问一个 yes/no 的问题
<input v-model="question"></input>
{{answer}}
</div>
<script type="module">
import { createApp, ref, watch } from './node_modules/vue/dist/vue.esm-browser.js'
createApp({
setup() {
const question = ref('')
const answer = ref('')
watch(question, async (newValue, oldValue) => {
const response = await fetch('https://www.yesno.wtf/api')
const data = await response.json()
answer.value = data.answer
})
return {
question,
answer
}
}
}).mount('#app')
</script>
</body>
</html>
6、watchEffect
- 是watch 函数的简化版本,也用来监视数据的变化
- 接收一个函数作为参数,监听函数内响应式数据的变化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<button @click="increase">increase</button>
<button @click="stop">stop</button>
<br>
{{count}}
</div>
<script type="module">
import { createApp, ref, watchEffect } from './node_modules/vue/dist/vue.esm-browser.js'
createApp({
setup() {
const count = ref(0)
const stop = watchEffect(() => {
console.log(count.value)
})
return {
count,
stop,
increase: () => {
count.value++
}
}
}
}).mount('#app')
</script>
</body>
</html>