注:本文是大圣老师课程的笔记,原课程地址:06 | 新的代码组织方式:Composition API + 到底好在哪里? (geekbang.org)
一,使用setup之后的改变
首先新建一个todoList.vue文件,然后写入如下代码:
<template>
<div>
<h1 @click="add">{
{
count}}</h1>
</div>
</template>
<script setup>
import {
ref } from "vue";
let count = ref(1)
function add(){
count.value++
}
</script>
<style>
h1 {
color: red;
}
</style>
在 script setup语法中,我们使用引入的 ref 函数包裹数字,返回的 count 变量就是响应式的数据,使用 add 函数实现数字的修改。需要注意的是,对于 ref 返回的响应式数据,我们需要修改 .value 才能生效,而在 script setup 标签内定义的变量和函数,都可以在模板中直接使用。
也就是说,从上面代码看,相较于vue2来说,有这点改变:
1,不再有export default,然后data,methods,components等的写法了,而是直接从vue引入相关api如(ref)来实现代码。
紧接着,把这个组件引入到home页面使用:
<template>
<h1>这是首页</h1>
<TodoList />
</template>
<script setup>
import TodoList from '../components/TodoList.vue'
</script>
可以看到一个新的改变:
2,vue3的setup会自动注册组件,这样就减少了注册组件的一步。而可以直接使用。
完善代码后:
<template>
<div>
<div class="title">
<input type="text" @keypress.enter="add" v-model="title" />
<button v-if="active < all" @click="clear">清理</button>
</div>
<div class="content">
<ul v-if="todoList.length">
<li v-for="(item, index) in todoList" :key="index">
<input type="checkbox" v-model="item.done" />
<span :class="[item.done ? 'inactive' : 'active']">
{
{
item.content }}
</span>
</li>
</ul>
<div v-else>暂无数据</div>
</div>
全选 {
{
active }} / {
{
all }}
</div>
</template>
<script setup>
import {
ref,computed} from "vue"
//把这个useTodo解耦出来
function useTodos() {
let title=ref("")
let todoList=ref([
{
content:"五湖四海皆一望",
done:false
},{
content:"千江有水千江月",
done:true}
])
function add() {
const obj = {
content: title.value,
done: false
};
todoList.value.push(obj);
title.value = "";
}
function clear() {
todoList.value = todoList.value.filter((v) => !v.done)
}
let active=computed(()=>{
return todoList.value.filter((v) => !v.done).length
})
let all = computed(() => todoList.value.length);
let allDone = computed(
{
get: function () {
return active.value === 0;
},
set: function (value) {
todoList.value.forEach((todo) => {
todo.done = value; });
},
}
);
return {
title,todoList,add,clear,active,all,allDone}
}
//其实你可以把组件内部的任何一段代码,从组件文件里抽离出一个独立的文件进行维护。
//再在这个组件中使用,于是这些东西就不依赖于this上下文了,这里再解构赋值出来
let {
title, todoList, add, clear, active, all, allDone } = useTodos();
import {
useMouse} from '../utils/mouse'
let {
x,y} = useMouse()
</script>
<style scoped>
</style>
这里又可以看到两个新的改变:
3,computed不再在return default里面,而是通过vue导入来使用,具体的计算属性作为参数传入。
4,和这个表单相关的功能,我们用useTodos函数包裹起来,又因为是ref实现的,和本组件解耦了,于是可以在想要的地方维护。不一定要放在本组件中,只要需要时引入使用即可。
二,解耦功能js代码的示例:
例如一个获取鼠标实时位置的功能,可以在util中新建这个文件:
import {
ref, onMounted,onUnmounted} from 'vue'
export function useMouse(){
const x = ref(0)
const y = ref(0)
function update(e) {
x.value = e.pageX
y.value = e.pageY
console.log("测试鼠标",x.value,y.value)
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return {
x, y }
}
然后只要在想要的地方引入使用就可以了:
import {
useMouse} from '../utils/mouse'
let {
x,y} = useMouse()
三,css样式中也可以使用属性绑定js中的变量
<template>
<div class="todoBox">
<div class="title">
<input type="text" @keypress.enter="add" v-model="title" />
<button v-if="active < all" @click="clear">清理</button>
</div>
<div class="content">
<ul v-if="todoList.length">
<li v-for="(item, index) in todoList" :key="index">
<input type="checkbox" v-model="item.done" />
<span :class="[item.done ? 'inactive' : 'active']">
{
{
item.content }}
</span>
</li>
</ul>
<div v-else>暂无数据</div>
</div>
全选 {
{
active }} / {
{
all }}
</div>
</template>
<script setup>
import {
ref,computed} from "vue"
//把这个useTodo解耦出来
function useTodos() {
let title=ref("")
let todoList=ref([
{
content:"五湖四海皆一望",
done:false
},{
content:"千江有水千江月",
done:true}
])
function add() {
const obj = {
content: title.value,
done: false
};
todoList.value.push(obj);
title.value = "";
}
function clear() {
todoList.value = todoList.value.filter((v) => !v.done)
}
let active=computed(()=>{
return todoList.value.filter((v) => !v.done).length
})
let all = computed(() => todoList.value.length);
let allDone = computed(
{
get: function () {
return active.value === 0;
},
set: function (value) {
todoList.value.forEach((todo) => {
todo.done = value; });
},
}
);
return {
title,todoList,add,clear,active,all,allDone}
}
//其实你可以把组件内部的任何一段代码,从组件文件里抽离出一个独立的文件进行维护。
//再在这个组件中使用,于是这些东西就不依赖于this上下文了,这里再解构赋值出来
let {
title, todoList, add, clear, active, all, allDone } = useTodos();
import {
useMouse} from '../utils/mouse'
let {
x,y} = useMouse()
//定义这个color变量
let color=ref("red")
</script>
<style scoped>
.active{
color:v-bind(color)
}
</style>
需要注意的是,color不能写在函数useToDo里面,因为函数外部读取不到,如果写里面,则还需要return,然后解构赋值才能使用。
实现的效果: