Vue 2.x 代码写法
<template>
<div class="search">
<form>
<input v-model="searchValue" type="text" />
<button @click="search"></button>
</form>
</div>
<ul class="result">
<li class="result__item" v-for="item in filterData" :key="item.id">
{{ item.name }}
</li>
</ul>
<span v-if="loading">Loading</span>
</template>
<script>
export default {
data() {
searchValue: '',
loading: true,
searchResult: []
},
computed: {
filterData() {
return searchResult.filter(i => i.id > 3)
}
},
methods: {
async search() {
this.loading = true
const { data } = await fetch('/search', body: this.searchValue.trim())
this.searchResult = data.toJSON()
this.loading = false
}
},
mounted() {
this.search()
}
}
</script>
使用 Composition API 下工作的代码
明显变化:
- 组件从原本的选项配置变成了函数定义
- 组件也不需要使用 this 去指定当前组件执行的上下文
<template>
<div class="search">
<form>
<input v-model="state.searchValue" type="text" />
<button @click="search"></button>
</form>
<ul class="result">
<li class="result__item" v-for="item in filterData" :key="item.id">
{{ item.name }}
</li>
</ul>
<span v-if="state.loading">Loading</span>
</div>
</template>
<script>
import { reactive, computed, onMounted, toRef } from '@vue/composition-api'
export default {
setup() {
// 初始化数据
const state = reactive({
searchValue: '',
loading: true,
searchResult: []
})
const filterData = computed(() => state.searchResult.filter(i => i.id > 3))
async function search() {
state.loading = true
const { data } = await fetch('/search', body: this.searchValue.trim())
state.searchResult = data.toJSON()
state.loading = false
}
onMounted(() => {
search()
})
return { ...toRef(state), filterData, search }
}
}
</script>
逻辑分离和复用
<script>
import { reactive, computed, onMounted, toRef, ref } from '@vue/composition-api'
// 方法提取
function useSearch() {
const searchValue = ref('')
const searchResult = ref([])
const loading = ref(true)
async function search() {
loading.value = true
const { data } = await fetch('/search', body: searchValue.trim())
searchResult.value = data.toJSON()
loading.value = false
}
onMounted(() => search())
return { searchValue, searchResult, loading, search }
}
// 提取计算属性
function useFilterSearchResult(searchResult) {
const filterData = computed(() => searchResult.value.filter(I=》 i.id > 3))
return { filterData }
}
export default {
setup(props, context) {
const search = useSearch()
return {
...search,
...useFilterSearchResult(search.searchResult)
}
}
}
</script>
缺点 (数据无响应情况)
当state作为一个返回值或参数的时候,它实际是作为一个值传递到了另外一个方法中,所以getter、setter将会丢失,数据无法响应。引用传递及值传递
function useMounsePosition(){
const pos = reactive({
x: 0,
y: 0
})
onMount(() => {})
return pos
}
# 数据响应丢失清空
export default {
setup() {
// 这里只取了 useMousePosition 返回值的引用值
// 而值里面的 getter / setter 丢失
const { x, y } = useMousePosition()
// 响应丢失
return { x, y }
// 响应丢失
return { ...useMousePosition() }
// 可以工作
return {
pos: useMousePosition()
}
}
}
解决方案一 使用 toRefs
function useMounsePosition(){
const pos = reactive({
x: 0,
y: 0
})
onMount(() => {})
return toRefs(pos)
}
export default {
setup() {
// 正确
const { x, y } = useMousePosition()
return { x, y }
// 正确
return { ...useMousePosition() }
}
}
解决方案二 使用 ref去初始数据
unction useMounsePosition(){
const x = ref(0)
const y = ref(0)
onMount(() => {
document.body.addeventListener("mousemove", (e) => {
x.value = e.x
y.value = e.y
})
})
return { x, y }
}
export default {
setup() {
// 正确
const { x, y } = useMousePosition()
return { x, y }
// 正确
return { ...useMousePosition() }
}
}