当前位置:   article > 正文

3.3Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3框架-企业级应用-Vue组合式API

3.3Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3框架-企业级应用-Vue组合式API

为什么要使用Composition API

一个Options API实例

在前面的课程中,我们都是采用 Options API(基于选项的 API ) 来写一个组件的。下面是一个实例:

  1. <template>
  2. Count is: {{ count }}, doubleCount is: {{ doubleCount }}
  3. <button @click="add"></button>
  4. </template>
  5. <script>
  6. export default {
  7. data() {
  8. return {
  9. count: 0,
  10. };
  11. },
  12. computed: {
  13. doubleCount() {
  14. return this.count * 2;
  15. },
  16. },
  17. methods: {
  18. add() {
  19. this.count++;
  20. }
  21. }
  22. }
  23. </script>

当要去理解一个组件时,我们更加关心的是:“这个组件是要干什么(即代码背后的意图)”,而不是:“这个组件用到了什么选项”。

Options API 撰写出来的代码自然采用了后者的表述方式,然而对前者的表述并不好。

Options API存在的问题

在 Options API 中实际上形成了一种强制的约定:

props 里面设置接收参数

data 里面设置变量

computed 里面设置计算属性

watch 里面设置监听属性

methods 里面设置事件方法

我们会发现: Options API 都约定了我们该在哪个位置做什么事,这在一定程度上也强制我们进行了代码分割。这就为展示背后的逻辑关注点设置了障碍。我们必须不断地在选项代码块之间“跳转”,以找到与该关注点相关的部分。

尤其是在大型组件中,数据与方法会很多,而数据与其相关联的方法就会被其他数据和方法分隔的很远,往往很难被看出它们之间的关联。

这是一个大型组件的示例,其中逻辑关注点是按颜色分组。

这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。

如果我们能够将与同一个逻辑关注点相关的代码配置在一起,这样会更好。而这正是组合式 API 使我们能够做到的。

Composition API简介

Composition API:组合式 API;一组低侵入式的、函数式的 API,使得我们能够更灵活地【组合】组件的逻辑。这是有别于 Options API 的一种函数式 API。无需通过很多选项来完成业务逻辑,Composition API提供了一个setup函数,我们可以将data数据、计算属性、方法等等,都放在setup函数中,这样就可以对业务进行集中处理了。

采用Composition API来重写上面的组件:

  1. <template>
  2. Count is: {{ state.count }}, doubleCount is: {{ state.doubleCount }}
  3. <button @click="add"></button>
  4. </template>
  5. <script>
  6. import { reactive, computed } from "vue";
  7. export default {
  8. setup() {
  9. const state = reactive({
  10. count: 0,
  11. doubleCount: computed(() => state.count * 2),
  12. });
  13. function add() {
  14. state.count++;
  15. }
  16. return {
  17. state,
  18. add
  19. }
  20. }
  21. }
  22. </script>

还有一个 setup 函数,setup 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点,如

果 setup 返回一个对象,则对象的属性将会被合并到组件模板的渲染上下文,我们就可以在模板里使用对应

的属性和方法。

Composition API

setup()入口

setup 函数是一个新的组件选项,它是在组件内使用 Composition API 的入口点。它会在Vue实例创建完成前被调

用。所以,setup函数中没有this指针

  1. <template>
  2. <div></div>
  3. </template>
  4. <script>
  5. export default {
  6. setup() {
  7. //这里书写本地状态(data数据)、计算属性或方法等
  8. console.log('setup函数');
  9. }
  10. }
  11. </script>

如果 setup 返回一个对象,则对象的属性将会被合并到组件模板的渲染上下文,我们就可以在模板里使用对应的属性和方法。所以,我们可以将本地状态(data数据)、方法、计算属性等写在 setup 函数中。

  1. <template>
  2. Count is: {{ count }}
  3. </template>
  4. <script>
  5. export default {
  6. setup() {
  7. let count = 10;
  8. return {
  9. count
  10. }
  11. }
  12. }
  13. </script>

上面代码中,在 setup 函数中声明了一个 count 数据。然后使用 return 返回需要暴露的内容。运行之后可以看到:视图能够正确显示count数据。

setup函数总结:

setup函数是Composition API 的入口点,是它的核心。

由于执行 setup 时,组件实例尚未被创建,因此在 setup 中不能使用 this。

setup中定义的东西必须要return出去,才能被使用或绑定视图。

ref 响应式监听

上面实例中,虽然视图能够显示数据。但当改变数据时,视图却不会得到响应。

  1. <template>
  2. Count is: {{ count }}
  3. <button @click="add"></button>
  4. </template>
  5. <script>
  6. export default {
  7. setup() {
  8. let count = 10;
  9. function add(){
  10. count++; //setup函数中没有this指针
  11. }
  12. return {
  13. count,
  14. add
  15. }
  16. }
  17. }
  18. </script>

原因很简单,count只是声明的一个普通数据,不具备响应功能。

在 Vue 3.0 中,我们可以通过一个 ref 函数来实现响应式数据监听。ref 接受一个参数,并将其包裹在一个带有value 属性的对象中返回,然后可以使用该 value 属性访问或更改响应式变量的值:

  1. <template>
  2. Count is: {{ count }}
  3. <button @click="add"></button>
  4. </template>
  5. <script>
  6. //注意:要导入ref
  7. import {ref} from 'vue';
  8. export default {
  9. setup() {
  10. let count = ref(10); //count成为响应式数据。
  11. function add(){
  12. count.value++; //使用value属性获取响应数据
  13. }
  14. return {
  15. count,
  16. add
  17. }
  18. }
  19. }
  20. </script>

为什么要将值封装在一个对象中,看似没有必要,但为了保持 JavaScript 中不同数据类型的行为统一,这是必须的。因为在 JavaScript 中,Number 或 String 等基本类型是通过值传递的,而不是通过引用传递的:

reactive与toRefs

上面实例中,操作数据时需要使用 value 属性,比较麻烦。

可以使用 reactive 与 toRefs 解决这个问题。首先使用 reactive 创建响应式对象,封装数据。

  1. <template>
  2. <p>Count is: {{ state.count }}</p>
  3. <button @click="add"></button>
  4. <p>{{ state.user.username }}</p>
  5. </template>
  6. <script>
  7. //注意:要导入ref
  8. import {reactive} from 'vue';
  9. export default {
  10. setup() {
  11. //所有响应数据都声明在这里,包括对象、数组
  12. const state = reactive({
  13. count: 10,
  14. user:{
  15. userId: 1,
  16. username: '张三'
  17. }
  18. })
  19. function add(){
  20. state.count++; //这里可以不使用value了
  21. }
  22. return {
  23. state,
  24. add
  25. }
  26. }
  27. }
  28. </script>

此时不用使用 value 属性了。

但是因为只有state是响应式数据,而state中的那些数据还不是响应式的。所以在视图访问数据时都需要使用 state作为前缀才可以。这就比较麻烦了。

此时我们可以使用 toRefs 进行优化。toRefs可以将state中的每一个数据进行展开,且都包装成响应数据。这样视图层就可以直接使用了。

  1. <template>
  2. <p>Count is: {{ count }}</p>
  3. <button @click="add"></button>
  4. <p>{{ user.username }}</p>
  5. </template>
  6. <script>
  7. //注意:要导入ref
  8. import {reactive, toRefs} from 'vue';
  9. export default {
  10. setup() {
  11. //所有响应数据都声明在这里,包括对象、数组
  12. const state = reactive({
  13. count: 10,
  14. user:{
  15. userId: 1,
  16. username: '张三'
  17. }
  18. })
  19. function add(){
  20. state.count++; //这里可以不使用value了
  21. }
  22. return {
  23. ...toRefs(state), //这里使用使用 ...toRefs(state)
  24. add
  25. }
  26. }
  27. }
  28. </script>

在返回时使用 ...toRefs(state) ,这样视图层就可以不使用 state 前缀了。

为什么要使用 ... 参数扩展运输符呢?因为toRefs(state) 将state对象展开,并包装成多个响应数据。

computed的用法

  1. <template>
  2. <p>Count is: {{ count }}</p>
  3. <p>doubleCount is: {{ doubleCount }}</p>
  4. <button @click="add"></button>
  5. <p>{{ user.username }}</p>
  6. </template>
  7. <script>
  8. //注意:要导入ref
  9. import { reactive, toRefs, computed } from "vue";
  10. export default {
  11. setup() {
  12. //所有响应数据都声明在这里,包括对象、数组
  13. const state = reactive({
  14. count: 10,
  15. user: {
  16. userId: 1,
  17. username: "张三",
  18. },
  19. doubleCount: computed(() => { //使用computed函数
  20. return state.count * 2;
  21. }),
  22. });
  23. function add() {
  24. state.count++; //这里可以不使用value了
  25. }
  26. return {
  27. ...toRefs(state),
  28. add,
  29. };
  30. },
  31. };
  32. </script>

首先要import导入computed。

在reactive({})中声明computed即可。

到现在为止,响应式数据就都可以处理了。

watch的用法

  1. <template>
  2. <div>
  3. {{ num }}
  4. <button @click="add"></button>
  5. </div>
  6. </template>
  7. <script>
  8. import { reactive, toRefs, watch } from "vue";
  9. export default {
  10. setup() {
  11. const state = reactive({
  12. num: 0,
  13. });
  14. watch(state,(newValue, oldValue) => {
  15. console.log(newValue, oldValue);
  16. }
  17. );
  18. function add() {
  19. state.num++;
  20. }
  21. return {
  22. ...toRefs(state),
  23. add,
  24. };
  25. },
  26. };
  27. </script>

使用watch函数来进行数据监听。watch函数有两个参数。

第一个参数:要监听的数据。

第二个参数:触发监听时的处理函数(包括newValue, oldValue)

上面实例中直接监听state响应对象。但我们知道,在state中会有很多数据,如果只想监听其中的某个数据,就需要换一种写法:

  1. watch(() => state.num,(newValue, oldValue) => {
  2. console.log(newValue, oldValue);
  3. });

第一个参数要写成函数返回值的形式,这样就能监听state响应对象中的某个数据了。

setup()参数

setup() 函数有两个参数:props 和 context。

为什么要有这两个参数呢?我们知道父子组件之间是可以传值。但是现在我们的业务逻辑都写在setup函数中,而setpu中没有this指针,那么就只能靠这两个参数来进行传递了。

props:父组件向子组件传值的参数。

context:子组件向父组件传值的参数。

props参数

setup() 函数的 props 是父组件向子组件传值的参数。

在components文件夹中创建子组件(Hello.vue):

  1. <template>
  2. <div>我是子组件</div>
  3. </template>
  4. <script>
  5. export default {
  6. setup(props, context) {
  7. console.log(props.msg)
  8. },
  9. props: {
  10. msg: String,
  11. },
  12. };
  13. </script>
  14. <style>
  15. </style>

父组件(HomeView.vue):

  1. <template>
  2. <div>
  3. <Hello msg="hello"></Hello>
  4. </div>
  5. </template>
  6. <script>
  7. import Hello from '../components/Hello.vue'
  8. import { reactive, toRefs, computed } from "vue";
  9. export default {
  10. setup() {
  11. const state = reactive({
  12. });
  13. return {
  14. ...toRefs(state),
  15. };
  16. },
  17. components:{
  18. Hello
  19. }
  20. };
  21. </script>

注意,要先import导入子组件,然后使用components挂载子组件。

context参数

setup() 函数的 context 是子组件向父组件传值的参数。

子组件(Hello.vue):

  1. <template>
  2. <div>
  3. <div>我是子组件</div>
  4. <button @click="send">给父组件发数据</button>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. setup(props, context) {
  10. function send() {
  11. context.emit("childmsg", "hello world!");
  12. }
  13. return {
  14. send,
  15. };
  16. },
  17. props: {
  18. msg: String,
  19. },
  20. };
  21. </script>
  22. <style>
  23. </style>

父组件(HomeView.vue):

  1. <template>
  2. <div>
  3. <Hello msg="hello" @childmsg="get"></Hello>
  4. <p>我是父组件,接受子组件传的值:{{welcome}}</p>
  5. </div>
  6. </template>
  7. <script>
  8. import Hello from '../components/Hello.vue'
  9. import { reactive, toRefs, computed } from "vue";
  10. export default {
  11. setup() {
  12. //所有响应数据都声明在这里,包括对象、数组
  13. const state = reactive({
  14. welcome: ''
  15. });
  16. function get(param) {
  17. state.welcome = param;
  18. }
  19. return {
  20. ...toRefs(state),
  21. get
  22. };
  23. },
  24. components:{
  25. Hello
  26. }
  27. };
  28. </script>

Composition API的使用

下面我们会将前面学过的知识点都改写为Composition API的形式。而且,Vue3兼容Options API和

Composition API两种写法。所以这两种写法都要会。

provide与inject的使用

我们学过provide与inject可用于多级组件直接传递数据,下面学习provide与inject在Composition API中的使用。

1.创建孙子组件(SubHello.vue)

  1. <template>
  2. <div>
  3. <div>我是孙组件</div>
  4. </div>
  5. </template>
  6. <script>
  7. import { inject } from "vue";
  8. export default {
  9. setup(props, context) {
  10. console.log(inject('msg'))
  11. return {};
  12. }
  13. };
  14. </script>

在孙子组件中import导入inject,并使用inject接收上级组件的传值。

2.在子组件(Hello.vue)中使用孙子组件

  1. <template>
  2. <div>
  3. <div>我是子组件</div>
  4. <SubHello></SubHello>
  5. </div>
  6. </template>
  7. <script>
  8. import SubHello from './SubHello.vue'
  9. export default {
  10. setup(props, context) {
  11. return {};
  12. },
  13. components:{
  14. SubHello
  15. }
  16. };
  17. </script>
  18. <style>
  19. </style>

3.在父组件中使用provide给多级组件传值

  1. <template>
  2. <div>
  3. <Hello></Hello>
  4. </div>
  5. </template>
  6. <script>
  7. import Hello from "../components/Hello.vue";
  8. import { provide } from "vue";
  9. export default {
  10. setup() {
  11. provide('msg','hello');
  12. },
  13. components:{
  14. Hello
  15. }
  16. };
  17. </script>

注意,由于父组件向孙子组件传递数据是单向的,所以孙子组件不能修改传递的值。如果子组件

vue生命周期的用法

在 setup () 内部调用生命周期钩子:

注意:在Composition API中没有beforeCreate()和created()这里两个声明周期函数了,统一使用setup()。

实例

  1. <template>
  2. <div>
  3. {{ num }}
  4. <button @click="add"></button>
  5. </div>
  6. </template>
  7. <script>
  8. import {
  9. reactive,toRefs,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted }
  10. from "vue";
  11. export default {
  12. setup() {
  13. const state = reactive({
  14. num: 1,
  15. });
  16. function add() {
  17. state.num++;
  18. }
  19. onBeforeMount(() => {
  20. console.log("DOM挂载前!");
  21. });
  22. onMounted(() => {
  23. console.log("DOM挂载后!");
  24. });
  25. onBeforeUpdate(() => {
  26. console.log("数据更新前!");
  27. })
  28. onUpdated(() => {
  29. console.log("数据更新后!");
  30. })
  31. onBeforeUnmount(() => {
  32. console.log("实例卸载前!");
  33. })
  34. onUnmounted(() => {
  35. console.log("实例卸载后!");
  36. })
  37. return {
  38. ...toRefs(state),
  39. add,
  40. };
  41. },
  42. };
  43. </script>

编程式路由的使用

下面学习如何在Composition API中使用路由。

打开App.vue组件,这里已经有了路由。当然,是使用router-link标签来实现的。现在我们将它改成编程式路由。

  1. <template>
  2. <nav>
  3. <!--
  4. <router-link to="/">Home</router-link> |
  5. <router-link to="/about">About</router-link>
  6. -->
  7. <button @click="toHome">Home</button>
  8. <button @click="toAbout">About</button>
  9. </nav>
  10. <router-view />
  11. </template>
  12. <script>
  13. import { useRouter } from "vue-router";
  14. export default{
  15. setup() {
  16. const router = useRouter();
  17. function toHome(){
  18. router.push('/');
  19. }
  20. function toAbout(){
  21. router.push({path:'/about',query:{name:'zhangsan'}});
  22. }
  23. return {
  24. toHome,
  25. toAbout
  26. }
  27. },
  28. }
  29. </script>

先import导入useRouter模块。

通过useRouter模块获取router对象。以后的路由写法就与前面所学一样了。

下面是获取路由参数,打开AboutView.vue文件

  1. <template>
  2. <div>
  3. </div>
  4. </template>
  5. <script>
  6. import { useRoute } from "vue-router";
  7. export default {
  8. setup(){
  9. const route = useRoute();
  10. console.log(route.query.name);
  11. }
  12. }
  13. </script>

通过同样的方式获取route对象后就可以获取路由参数了。

Vuex的使用

下面学习如何在Composition API中使用Vuex。

  1. <template>
  2. <div>
  3. </div>
  4. </template>
  5. <script>
  6. import { useStore } from "vuex";
  7. export default {
  8. setup() {
  9. const store = useStore();
  10. console.log(store.state.num);
  11. console.log(store.getters.newnum);
  12. }
  13. };
  14. </script>

先import导入useStore模块。

通过useStore模块获取store对象。就可以通过store对象获取Vuex中的所有数据了。

获取DOM的使用

前面我们知道在Vue中,可以使用ref来获取DOM对象。下面学习如何在Composition API中使用ref。

  1. <template>
  2. <div ref="myRef">获取单个DOM元素</div>
  3. </template>
  4. <script>
  5. import { ref, onMounted } from 'vue';
  6. export default {
  7. setup() {
  8. const myRef = ref(null); //ref(null)是一个固定的写法
  9. onMounted(() => {
  10. console.dir(myRef.value);
  11. });
  12. return {
  13. myRef
  14. };
  15. }
  16. };
  17. </script>

在HTML标签中使用 ref 属性标识一个DOM对象。

需要 import 导入 ref 对象。

使用 const myRef = ref(null); 的方式获取包装好的DOM对象,命名为HTML中的 ref 属性名。并且此数据需

要暴露出去。

使用 value 属性即可获取 DOM对象。

使用Composition API重写todoList

AddNew组件

  1. <template>
  2. <div>
  3. <input type="text" v-model="newItem" />
  4. <button @click="handleAdd">添加</button>
  5. </div>
  6. </template>
  7. <script>
  8. import {reactive, toRefs} from 'vue';
  9. export default {
  10. setup(props, context){
  11. const state = reactive({
  12. newItem: ""
  13. })
  14. function handleAdd() {
  15. if (state.newItem == "") {
  16. alert("不能为空");
  17. return;
  18. }
  19. //注意:这里使用setup参数context来出发父组件事件
  20. context.emit("submitNewItem", state.newItem);
  21. state.newItem = "";
  22. }
  23. return {
  24. ...toRefs(state),
  25. handleAdd
  26. }
  27. }
  28. }
  29. </script>

TheList组件

  1. <template>
  2. <ol>
  3. <li v-for="(item, index) in list" :key="index" @click="judgeItem(index)">
  4. {{ item }}
  5. </li>
  6. </ol>
  7. </template>
  8. <script>
  9. export default {
  10. setup(props, context) {
  11. //这里分别使用了setup的两个参数
  12. function judgeItem(index) {
  13. if (props.listType) {
  14. context.emit("handleDelete", index);
  15. } else {
  16. context.emit("handleJudge", index);
  17. }
  18. }
  19. return {
  20. judgeItem
  21. };
  22. },
  23. props: {
  24. list: {
  25. type: Array,
  26. required: true,
  27. },
  28. listType: {
  29. type: Boolean,
  30. default: false,
  31. },
  32. },
  33. };
  34. </script>

TodoList组件

  1. <template>
  2. <div>
  3. <h1>todoList</h1>
  4. <AddNew @submitNewItem="addNewItem"></AddNew>
  5. <TheList :list="todoList" @handleJudge="toDone"></TheList>
  6. <hr />
  7. <TheList :list="doneList" :listType="true" @handleDelete="toDelete"></TheList>
  8. </div>
  9. </template>
  10. <script>
  11. import AddNew from "../components/AddNew.vue";
  12. import TheList from "../components/TheList.vue";
  13. import {reactive, toRefs} from 'vue';
  14. export default {
  15. setup(){
  16. const state = reactive({
  17. todoList: [], //待办事项
  18. doneList: [] //完成事项
  19. })
  20. function addNewItem(newItem){
  21. state.todoList.push(newItem);
  22. }
  23. function toDone(index){
  24. state.doneList.push(state.todoList.splice(index,1)[0]);
  25. }
  26. function toDelete(index){
  27. state.doneList.splice(index,1);
  28. }
  29. return {
  30. ...toRefs(state),
  31. addNewItem,
  32. toDone,
  33. toDelete
  34. }
  35. },
  36. components: {
  37. AddNew,
  38. TheList,
  39. },
  40. };
  41. </script>

setup语法糖

在Composition API中,在setup函数中声明的数据、函数等内容,都需要通过 return 对外暴露,才能被组件的视图模板(template)使用,这就造成了书写上的不方便。于是,Vue官方又给我们推出了一个新的setup语法糖。

使用setup语法糖,就可以不用写setup函数了。并且,数据和函数也不用返回,组件也不需要注册了。

setup语法糖的基本结构

  1. <template>
  2. </template>
  3. <script setup>
  4. //此处直接写setup函数中的内容
  5. </script>
  6. <style>
  7. </style>

在script标签中使用setup属性即可。

运行时,script标签中的内容会被重新编译成 setup() 函数的形式。

而且,声明的数据、函数不需要通过 return 暴露,即可被 template所使用

响应数据的使用

  1. <template>
  2. <div>
  3. <p>{{ num }}</p>
  4. <button @click="add"></button>
  5. </div>
  6. </template>
  7. <script setup>
  8. let num = 10;
  9. //const num = 10;
  10. //由于num不是响应数据,所以改变num是无效的。
  11. const add = ()=>{
  12. alert("触发了此方法");
  13. num++;
  14. }
  15. </script>

直接声明的数据不是响应式的,数据改变时不会响应到视图模板中。

  1. <template>
  2. <div>
  3. <p>{{ num }}</p>
  4. <p>{{ dept.deptno }},{{ dept.dname }},{{ dept.loc }}</p>
  5. <ul>
  6. <li v-for="user in userArr" :key="user.userId">
  7. {{user.userId}},{{user.userName}},{{user.userAge}}
  8. </li>
  9. </ul>
  10. <button @click="add"></button>
  11. </div>
  12. </template>
  13. <script setup>
  14. import { reactive, ref } from "vue";
  15. const num = ref(10);
  16. const dept = reactive({
  17. deptno: 20,
  18. dname: "技术部",
  19. loc: '沈阳市',
  20. });
  21. const userArr = ref([
  22. {
  23. userId: 100,
  24. userName: "张三",
  25. userAge: 25,
  26. },
  27. {
  28. userId: 101,
  29. userName: "李四",
  30. userAge: 26,
  31. },
  32. {
  33. userId: 102,
  34. userName: "王五",
  35. userAge: 27,
  36. },
  37. ]);
  38. const add = () => {
  39. num.value++; //注意:要使用value属性获取
  40. dept.deptno++;
  41. //userArr.value[0].userAge++;
  42. userArr.value = [];
  43. }
  44. </script>

ref 和 reactive 都可以做响应式数据,它们的区别如下:

reactive:用于定义引用类型。只能修改数据,不能改变其引用。

ref:用于定义基本类型和引用类型。可以修改数据,也可以改变其引用。

在方法中修改数据时需要使用 value属性。因为,Ref的本质是通过Reactive创建的,Ref(10) 就相当于:Reactive({value:10});

在视图模板调用可以省略value属性的书写。

其它语法的使用

下面例子演示了computed计算属性、watch监听、生命周期函数的使用。

  1. <template>
  2. <div>
  3. {{ num }}
  4. {{ newNum }}
  5. <button @click="add">add</button>
  6. </div>
  7. </template>
  8. <script setup>
  9. import { ref, computed, watch, onMounted } from 'vue';
  10. const num = ref(10);
  11. const newNum = computed(() => {
  12. return num.value*2;
  13. })
  14. const add = ()=>{
  15. num.value++;
  16. }
  17. watch(num,(newValue,oldValue)=>{
  18. console.log(newValue,oldValue);
  19. })
  20. //生命周期函数
  21. onMounted(() => {
  22. console.log("DOM挂载后!");
  23. });
  24. </script>

引入组件的使用

引入的组件不必注册,可以直接使用。

  1. <template>
  2. <div class="home">
  3. <HelloWorld msg="Welcome to Your Vue.js App"/>
  4. </div>
  5. </template>
  6. <script setup>
  7. // @ is an alias to /src
  8. import HelloWorld from '@/components/HelloWorld.vue'
  9. </script>

父子组件传值的使用

defineProps的使用

defineProps用于父组件向子组件传值。

父组件

  1. <template>
  2. <div class="home">
  3. <HelloWorld msg="Welcome to Your Vue.js App" :num="num"/>
  4. </div>
  5. </template>
  6. <script setup>
  7. // @ is an alias to /src
  8. import HelloWorld from '@/components/HelloWorld.vue'
  9. const num = 20
  10. </script>

子组件

  1. <template>
  2. <div class="hello">
  3. <h1>{{ msg }},{{ num }}</h1>
  4. </div>
  5. </template>
  6. <script setup>
  7. //const myProps = defineProps(['msg','num']);
  8. const myProps = defineProps({
  9. msg:{
  10. type: String
  11. },
  12. num:{
  13. type: Number,
  14. required: true
  15. }
  16. });
  17. </script>
  18. <style scoped>
  19. </style>

defineProps也可以有数组形式和对象形式两种写法。

defineEmits的使用

defineEmits用于子组件向父组件传值。

父组件

  1. <template>
  2. <div class="home">
  3. <HelloWorld
  4. msg="Welcome to Your Vue.js App"
  5. :num="num"
  6. @childmsg="get"/>
  7. </div>
  8. </template>
  9. <script setup>
  10. // @ is an alias to /src
  11. import HelloWorld from '@/components/HelloWorld.vue'
  12. const num = 20;
  13. const get = (value) => {
  14. console.log(value)
  15. }
  16. </script>

子组件

  1. <template>
  2. <div class="hello">
  3. <h1>{{ msg }},{{ num }}</h1>
  4. <button @click="send">给父组件传值</button>
  5. </div>
  6. </template>
  7. <script setup>
  8. const myProps = defineProps(['msg','num']);
  9. const emit = defineEmits(['childmsg']);
  10. const send = () => {
  11. emit('childmsg','子组件向父组件传的值');
  12. }
  13. </script>
  14. <style scoped>
  15. </style>

使用setup语法糖重写todoList

AddNew组件

  1. <template>
  2. <div>
  3. <input type="text" v-model="newItem" />
  4. <button @click="handleAdd">添加</button>
  5. </div>
  6. </template>
  7. <script setup>
  8. import { ref } from "vue";
  9. const newItem = ref("");
  10. const emit = defineEmits(["submitNewItem"]);
  11. const handleAdd = () => {
  12. if (newItem.value == "") {
  13. alert("不能为空");
  14. return;
  15. }
  16. emit("submitNewItem", newItem.value);
  17. newItem.value = "";
  18. };
  19. </script>

TheList组件

  1. <template>
  2. <ol>
  3. <li v-for="(item, index) in list" :key="index" @click="judgeItem(index)">
  4. {{ item }}
  5. </li>
  6. </ol>
  7. </template>
  8. <script setup>
  9. const emit = defineEmits(['handleDelete','handleJudge']);
  10. const judgeItem = (index) => {
  11. if (myProps.listType) {
  12. emit("handleDelete", index);
  13. } else {
  14. emit("handleJudge", index);
  15. }
  16. };
  17. const myProps = defineProps({
  18. list: {
  19. type: Array,
  20. required: true,
  21. },
  22. listType: {
  23. type: Boolean,
  24. default: false,
  25. },
  26. });
  27. </script>

TodoList组件

  1. <template>
  2. <div>
  3. <h1>todoList</h1>
  4. <AddNew @submitNewItem="addNewItem"></AddNew>
  5. <TheList :list="todoList" @handleJudge="toDone"></TheList>
  6. <hr />
  7. <TheList
  8. :list="doneList"
  9. :listType="true"
  10. @handleDelete="toDelete"
  11. ></TheList>
  12. </div>
  13. </template>
  14. <script setup>
  15. import AddNew from "../components/AddNew.vue";
  16. import TheList from "../components/TheList.vue";
  17. import { reactive } from "vue";
  18. const todoList = reactive([]); //待办事项
  19. const doneList = reactive([]); //完成事项
  20. const addNewItem = (newItem) => {
  21. todoList.push(newItem);
  22. }
  23. const toDone = (index) => {
  24. doneList.push(todoList.splice(index, 1)[0]);
  25. }
  26. const toDelete = (index) => {
  27. doneList.splice(index, 1);
  28. }
  29. </script>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/547624
推荐阅读
相关标签
  

闽ICP备14008679号