写一个todolist,大概长这样
vue2.xx 语法
<template>
<div>
<from>
<input type="text" v-model="stu.id">
<input type="text" v-model="stu.name">
<input type="text" v-model="stu.age">
<input type="submit" @click="addStu">
</from>
<ul>
<li v-for="(sta,index) in stus" :key="index" @click="remStu(index)">
{{sta.name}} -- {{sta.age}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {
stus: [
{ id: 1, name: "zs", age: 18 },
{ id: 2, name: "ww", age: 1892 },
{ id: 3, name: "ls", age: 120 },
{ id: 4, name: "zz", age: 19 },
],
stu: {
id: "",
name: "",
age: "",
},
// 新增功能1的数据
};
},
methods: {
remStu(index) {
this.stus.splice(index, 1);
},
addStu(e) {
e.preventDefault();
const stu = Object.assign({}, this.stu);
this.stus.push(stu);
this.stu.id = "";
this.stu.name = "";
this.stu.age = "";
},
// 新增功能1的业务逻辑
},
};
</script>
效果长这样
有新增功能,有删除功能(直接点 li 标签就删除它)。
vue2是数据和功能分离,创建一个功能1,需要创建功能1的数据,在创建功能1的业务逻辑
Vue3 期望用 组合API 的方式来解决一个应用中,数据和功能分离的问题。即方法和 data 里的数据隔了一层进行调用的问题
组合api
代码大概长这样
<template>
<div>
<h3>{{count}}</h3>
<button @click="myFn">按钮</button>
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "App",
// setu函数是组合api的入口函数
setup() {
// let count = 0;
// 定义了一个名称叫做count变量,这个变量的初始值是0
// 这个变量发生改变之后,vue会自动更新UI
let count = ref(0);
// 在组合api中,如果想定义方法,不用定义到methods中,直接定义即可
function myFn() {
// alert(123)
console.log("count", count.value);
count.value += 1;
}
// 注意点:
// 在组合api中定义的变量/方法,要想在外界使用,必须通过 return{xxx,xxx} 暴露出去
return { count, myFn };
},
components: {},
methods: {},
};
</script>
效果长这样
点击按钮 数字 +1
setup
、ref
、return
什么是 setup
,什么是 ref
,return
的又是什么鬼 可以先看下这篇文章 点击这里
# ref 什么是ref
Ref
是这样的一种数据结构:它有个key为Symbol
的属性做类型标识,有个属性value
用来存储数据。这个数据可以是任意的类型,唯独不能是被嵌套了Ref
类型的类型。
Ref
类型的数据,是一种响应式的数据。
Ref
写法简单,但也有弊端,它只能监听一些如数字、字符串、布尔之类的简单数据。复杂数据需要用到以后讲的 reactive
。(实际上也可以用 Ref
来封装对象,只不过在访问上多一层 value
,稍微麻烦了一些)。
具体 Ref
数据的结构长这样:
要更改它的数据,主要更改和关注它的 value
值就够了
# setup
setup
,就是我们最近老是能听到的 Composition API,组合式 API。关于这个 API 的细节,还请参阅官方文档,这里我只期望说一下简单的内容
setup
选项应该是一个接受 props
和 context
的函数。此外,我们从 setup
返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。
也就是说,setup
中创建并 return 的所有东西,都将被得到外部的解析,无论是过去在 data
中创建的数据也好,还是在 methods
创建的方法也好,都将变成允许被响应式地使用,仿佛 Vue2 中的这些 API 都被融合在一起了一样,而实际上 Vue3 也是为了实现这个目的。
有了这两点认识(ref
和setup
),我想上面的代码就变得简单了起来。回到刚刚的 Todo List,我们用这个 API 来实现试一下。
用组合 API 来实现 Todo List
<template> <div> <ul> <li v-for="(sta, index) in state.stus" :key="index" @click="remStu(index)"> {{ sta.id }}: {{ sta.name }} -- {{ sta.age }} </li> </ul> </div> </template> <script> import { reactive } from "vue"; export default { name: "App", // setu函数是组合api的入口函数 setup() { let state = reactive({ stus: [ { id: 1, name: "zs", age: 18 }, { id: 2, name: "ww", age: 1892 }, { id: 3, name: "ls", age: 120 }, { id: 4, name: "zz", age: 19 }, ], }); function remStu(index){ state.stus.splice(index, 1); } // let {state,remStu} = removeStu() return {state,remStu} }, components: {}, methods: { }, }; // 抽离 function removeStu(){ let state = reactive({ stus: [ { id: 1, name: "zs", age: 18 }, { id: 2, name: "ww", age: 1892 }, { id: 3, name: "ls", age: 120 }, { id: 4, name: "zz", age: 19 }, ], }); function remStu(index){ state.stus.splice(index, 1); } return {state,remStu} } </script>
这里引进了 reactive
,和 ref
一样,具体了解参考这篇文章,简单来说,就是复杂类型版本的ref
。只要你看懂了前文,这部分的代码对你来说不成问题。
ref函数只能监听简单类型的变化,不能监听复杂类型的变化(对象/数组)
todolist 新增删除
<template>
<div>
<form>
<input type="text" v-model="state2.stu.id" />
<input type="text" v-model="state2.stu.name" />
<input type="text" v-model="state2.stu.age" />
<input type="submit" @click="addStu" />
</form>
<ul>
<li
v-for="(sta, index) in state.stus"
:key="index"
@click="remStu(index)"
>
{{ sta.id }}: {{ sta.name }} -- {{ sta.age }}
</li>
</ul>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
// setu函数是组合api的入口函数
setup() {
let state = reactive({
stus: [
{ id: 1, name: "zs", age: 18 },
{ id: 2, name: "ww", age: 1892 },
{ id: 3, name: "ls", age: 120 },
{ id: 4, name: "zz", age: 19 },
],
});
function remStu(index) {
state.stus.splice(index, 1);
}
let state2 = reactive({
stu: {
id: "",
name: "",
age: "",
},
});
function addStu(e) {
e.preventDefault();
const stu = Object.assign({}, state2.stu);
state.stus.push(stu);
state2.stu.id = "";
state2.stu.name = "";
state2.stu.age = "";
}
return { state, remStu, state2, addStu };
},
};
</script>
效果这样
和最开始我们写的 Todo List 在方法上基本一致。而这些都不是重点,重点是通过这种组合 API 的方式,允许我们对数据和方法进行组合的包装,就像这样,我们可以把方法抽离出来单独管理
<template>
<div>
<form>
<input type="text" v-model="state2.stu.id" />
<input type="text" v-model="state2.stu.name" />
<input type="text" v-model="state2.stu.age" />
<input type="submit" @click="addStu" />
</form>
<ul>
<li
v-for="(sta, index) in state.stus"
:key="index"
@click="remStu(index)"
>
{{ sta.id }}: {{ sta.name }} -- {{ sta.age }}
</li>
</ul>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
// setu函数是组合api的入口函数
setup() {
let {state,remStu} = removeStu()
let {state2,addStu} = addStudent(state)
return { state, remStu, state2, addStu };
},
components: {},
methods: {},
};
// 抽离
// 删除数据
function removeStu() {
let state = reactive({
stus: [
{ id: 1, name: "zs", age: 18 },
{ id: 2, name: "ww", age: 1892 },
{ id: 3, name: "ls", age: 120 },
{ id: 4, name: "zz", age: 19 },
],
});
function remStu(index) {
state.stus.splice(index, 1);
}
return { state, remStu };
}
// 添加数据
function addStudent(state){
let state2 = reactive({
stu: {
id: "",
name: "",
age: "",
},
});
function addStu(e) {
e.preventDefault();
const stu = Object.assign({}, state2.stu);
state.stus.push(stu);
state2.stu.id = "";
state2.stu.name = "";
state2.stu.age = "";
}
return {state2,addStu}
}
</script>
上面是把方法抽离放到用一个组件里,还可以把方法单独抽离,单独放在js文件中,然后再在组件中引用,用export
和import
来进行交流
文件结构长这样
rem.js
import { reactive } from "vue";
// 删除数据
function removeStu() {
let state = reactive({
stus: [
{ id: 1, name: "zs", age: 18 },
{ id: 2, name: "ww", age: 1892 },
{ id: 3, name: "ls", age: 120 },
{ id: 4, name: "zz", age: 19 },
],
});
function remStu(index) {
state.stus.splice(index, 1);
}
return { state, remStu };
}
export default removeStu
add.js
import { reactive } from "vue";
// 添加数据
function addStudent(state) {
let state2 = reactive({
stu: {
id: "",
name: "",
age: "",
},
});
function addStu(e) {
e.preventDefault();
const stu = Object.assign({}, state2.stu);
state.stus.push(stu);
state2.stu.id = "";
state2.stu.name = "";
state2.stu.age = "";
}
return { state2, addStu }
}
export default addStudent
注意:每个js文件里面都要引入 reactive 方法 import { reactive } from "vue";