当前位置: 首页 > article >正文

Vue进阶之旅:组件通信与高级用法深度剖析(组件通信进阶用法)

Vue进阶之旅:组件通信与高级用法深度剖析

文章目录

  • Vue进阶之旅:组件通信与高级用法深度剖析
    • 一、组件的三大组成部分
    • 二、组件通信
      • (一)父子关系通信
      • (二)非父子关系通信
    • 三、综合案例:小黑记事本(组件版)
      • 1、拆分组件
      • 2、渲染待办任务
        • `TodoHeader`组件添加任务功能实现
      • 3、添加任务
        • 功能需求剖析
        • 子组件:数据收集与事件触发
        • 父组件:接收数据与添加任务
      • 4、**删除任务**
        • 功能实现的组件架构
        • 子组件`TodoMain`:触发删除事件
      • 5、**底部合计和清空功能**
        • 底部合计功能:父传子实现数据展示
        • 清空功能:子传父触发清空操作
      • 6、**持久化存储**
        • 持久化存储:使用`watch`监视数据变化
      • 7、总结
    • 四、进阶语法

在Vue开发的学习过程中,组件化开发是提升效率和代码可维护性的关键。今天深入学习了Vue组件的相关知识,涵盖组件的三大组成部分、组件通信以及一些进阶语法,下面将详细分享学习成果。

一、组件的三大组成部分

组件由结构、样式和逻辑三部分组成,各部分都有其独特的规则和注意点。

  1. 结构:组件的<template>部分定义结构,且有且只能有一个根元素。这确保了组件结构的规范性,利于Vue进行模板解析和渲染。例如:
<template>
  <div>
    <!-- 组件的具体内容 -->
  </div>
</template>
  1. 样式:组件样式分为全局样式和局部样式。全局样式会影响所有组件,而给组件添加scoped属性可创建局部样式,仅作用于当前组件。scoped的原理是为当前组件内标签添加data-v-hash值的属性,同时给CSS选择器添加[data-v-hash值]的属性选择器,使得样式仅对当前组件元素生效。示例如下:
<template>
  <div data-v-cbe7c9bc>
    <p data-v-cbe7c9bc>我是hm-header</p> 
  </div> 
  <div>我是普通盒子</div>
</template>
<style scoped>
  div[data-v-cbe7c9bc]{ 
    border: 1px solid #000;
    margin: 10px 0;
  }
</style>
  1. 逻辑:组件的逻辑部分在<script>中定义,其中data选项必须是一个函数。这样做能保证每个组件实例维护独立的数据对象,每次创建新组件实例时,都会执行data函数得到新对象,避免组件间数据相互干扰。如:
<script>
  export default {
    data() {
      return {
        count: 100
      }
    }
  }
</script>

二、组件通信

组件通信是组件化开发中实现数据交互的重要手段,不同组件关系对应不同通信方案。

(一)父子关系通信

  1. 父传子(props):父组件通过props向子组件传递数据。在父组件中,以添加属性的方式传值;子组件通过props选项接收并在模板中使用。代码示例如下:
    父组件App.vue
<template>
  <div id="app">
    <!-- 给子组件添加属性传值 -->
    <Son :title="msg"></Son> 
  </div>
</template>
<script>
  export default {
    data() {
      return {
        msg: '学前端来黑马'
      }
    }
  }
</script>

子组件Son.vue

<template>
  <div>
    我是子Son组件-{{title}}
  </div>
</template>
<script>
  export default {
    // 子组件内部通过props接收
    props: ['title'] 
  }
</script>
  1. **子传父( e m i t ) ∗ ∗ :子组件利用 ‘ emit)**:子组件利用` emit:子组件利用emit通知父组件修改更新。子组件触发事件并传递数据,父组件监听事件并提供处理函数。如下所示: 子组件Son.vue`:
<template>
  <div>
    我是Son组件{{title}}
    <button @click="changeTitle">修改标题</button> 
  </div>
</template>
<script>
  export default {
    props: ['title'],
    methods: {
      changeTitle() {
        // 触发事件并传递数据给父组件
        this.$emit('changeTitle', "传智教育") 
      }
    }
  }
</script>

父组件App.vue

<template>
  <div id="app">
    <!-- 父组件监听事件 -->
    <Son :title="msg" @changeTitle="handleChange"></Son> 
  </div>
</template>
<script>
  import Son from './components/Son'
  export default {
    data() {
      return {
        msg: '黑马程'
      }
    },
    methods: {
      // 处理子组件传递的数据
      handleChange(title) { 
        this.msg = title
      }
    }
  }
</script>

此外,props还可进行校验,包括类型校验、非空校验、设置默认值和自定义校验等,为组件的prop指定验证要求,帮助开发者快速发现错误。示例如下:

props: {
  // 类型校验
  age: Number, 
  // 非空校验和默认值
  username: {
    type: String,
    required: true,
    default: 'unknown'
  },
  // 自定义校验
  hobby: {
    type: Array,
    validator(value) {
      return value.length > 0
    }
  }
}

需注意,prop遵循单向数据流,其数据由外部传入,子组件不能直接修改,要通过$emit通知父组件修改,确保数据流向清晰。

(二)非父子关系通信

  1. event bus(事件总线):用于非父子组件间的简易消息传递,复杂场景可使用Vuex。首先创建一个能被所有组件访问的事件总线(空Vue实例),如utils/EventBus.js
import Vue from 'vue' 
const Bus = new Vue() 
export default Bus

接收方组件监听事件:

created () {
  Bus.$on('sendMsg', (msg) => {
    this.msg = msg
  })
}

发送方组件触发事件:

Bus.$emit('sendMsg', '这是一个消息')
  1. provide & inject:用于跨层级共享数据。父组件通过provide提供数据,子/孙组件通过inject取值使用。父组件示例:
export default {
  data() {
    return {
      color: 'red',
      userInfo: { name: 'John' }
    }
  },
  provide () {
    return {
      color: this.color, 
      userInfo: this.userInfo 
    }
  }
}

子/孙组件示例:

export default {
  created () {
    inject: ['color','userInfo'],
    console.log(this.color, this.userInfo)
  }
}

三、综合案例:小黑记事本(组件版)

通过小黑记事本案例,实践了组件通信及相关知识。该案例包含拆分组件、渲染任务、添加任务、删除任务、底部合计和清空功能以及持久化存储等核心步骤。

1、拆分组件

新建组件并合理存放,导入并注册使用,构建项目基础结构。

image-20250116100327652

2、渲染待办任务

公共父组件提供数据,通过父传子传递list,子组件使用v-for指令渲染任务列表。

####项目结构与组件关系概述

我们的小黑记事本应用包含了多个组件,其中父组件起到了数据管理和协调子组件的作用。在父组件App.vue中,我们看到如下代码:

<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader></TodoHeader>
    <TodoMain :list="list"></TodoMain>
    <TodoFooter></TodoFooter>
  </section>
</template>

<script>
import TodoFooter from './components/TodoFooter.vue';
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';

export default {
  data () {
    return {
      list: [
        { id: 1, name: '打篮球' },
        { id: 2, name: '看电影' },
        { id: 3, name: '逛街' },
      ],
    }
  },

  components : {
    TodoHeader,
    TodoMain,
    TodoFooter
  }
}
</script>

父组件管理着任务列表list数据,并将其传递给TodoMain组件用于展示。而TodoHeader组件将承担添加任务的功能,接下来我们重点关注TodoHeader组件如何实现添加任务的逻辑。

TodoHeader组件添加任务功能实现

TodoHeader组件中,我们将通过v-model指令收集用户输入的数据,然后通过事件监听和父子组件通信,将新任务传递给父组件,最后由父组件将新任务添加到任务列表中。

  1. TodoHeader组件模板(template):在TodoHeader组件的模板部分,添加一个输入框和一个按钮,用于用户输入新任务并触发添加操作。
<template>
  <div class="todo-header">
    <input v-model="newTask" type="text" placeholder="请输入新任务">
    <button @click="addTask">添加任务</button>
  </div>
</template>

这里,v-model="newTask"实现了输入框与组件内部数据newTask的双向绑定。用户在输入框中输入的内容会实时更新newTask的值,反之亦然。@click="addTask"为按钮绑定了一个点击事件,当用户点击按钮时,会触发addTask方法。
2. TodoHeader组件逻辑(script):在TodoHeader组件的<script>部分,定义newTask数据以及addTask方法。

<script>
export default {
  data() {
    return {
      newTask: ''
    }
  },
  methods: {
    addTask() {
      if (this.newTask.trim() !== '') {
        this.$emit('addTaskEvent', { id: Date.now(), name: this.newTask });
        this.newTask = ''; 
      }
    }
  }
}
</script>

data函数中,我们初始化了newTask为空字符串,用于存储用户输入的新任务。addTask方法首先检查newTask是否为空(去除首尾空格后),若不为空,则通过this.$emit('addTaskEvent', { id: Date.now(), name: this.newTask })触发一个自定义事件addTaskEvent,并将一个包含新任务idname的对象作为参数传递给父组件。这里使用Date.now()生成一个唯一的id,保证每个任务的id不同。最后,将newTask清空,以便用户输入下一个任务。
3. 父组件接收并添加任务:回到父组件,我们需要监听TodoHeader组件触发的addTaskEvent事件,并在事件处理函数中添加新任务到list数组。在父组件的<script>部分,添加如下代码:

<script>
import TodoFooter from './components/TodoFooter.vue';
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';

export default {
  data () {
    return {
      list: [
        { id: 1, name: '打篮球' },
        { id: 2, name: '看电影' },
        { id: 3, name: '逛街' },
      ],
    }
  },
  components : {
    TodoHeader,
    TodoMain,
    TodoFooter
  },
  methods: {
    handleAddTask(newTask) {
      this.list.unshift(newTask);
    }
  }
}
</script>

在父组件的methods中定义了handleAddTask方法,该方法接收TodoHeader组件传递过来的新任务对象,并使用unshift方法将新任务添加到list数组的开头。同时,在父组件的模板中,需要为TodoHeader组件添加事件监听:

<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader @addTaskEvent="handleAddTask"></TodoHeader>
    <TodoMain :list="list"></TodoMain>
    <TodoFooter></TodoFooter>
  </section>
</template>

@addTaskEvent="handleAddTask"表示当TodoHeader组件触发addTaskEvent事件时,会调用父组件的handleAddTask方法,并将TodoHeader组件传递的参数(即新任务对象)作为handleAddTask方法的参数。

通过以上步骤,我们成功实现了小黑记事本的添加任务功能。用户在TodoHeader组件的输入框中输入任务名称,点击添加按钮后,新任务会被添加到父组件的任务列表list中,并在TodoMain组件中展示出来。这个功能的实现,充分展示了Vue中组件通信和数据绑定的强大功能,为构建复杂的应用奠定了基础。

3、添加任务

通过v-model收集数据,监听事件,子传父传递任务,父组件使用unshift方法添加任务。

功能需求剖析

小黑记事本的添加任务功能要求用户在输入框输入任务名称后,点击添加按钮或按下回车键,新任务就能添加到任务列表顶部。为实现此功能,我们采用父子组件协同工作的模式。父组件负责管理任务列表数据,子组件TodoHeader承担用户输入的收集与事件触发。

子组件:数据收集与事件触发

TodoHeader组件代码如下:

<template>
  <!-- 输入框 -->
  <header class="header">
      <h1>小黑记事本</h1>
      <input @keyup.enter="HandleAdd" v-model="todoName" placeholder="请输入任务" class="new-todo" />
      <button @click="HandleAdd" class="add">添加任务</button>
    </header>
</template>

<script>
export default {
    data () {
        return {
            todoName :''
        }
    },

    methods: {
        HandleAdd () {
            if(this.todoName.trim() === ''){
                alert('任务名称不能为空!')
                return
            }
            this.$emit('add' , this.todoName)
            this.todoName = ''
        }
    },
}
</script>

在模板部分,<input>标签使用v-model="todoName"指令,在用户输入时自动将内容同步到组件的todoName数据属性,实现双向数据绑定。同时监听keyup.enter事件,当用户按下回车键时触发HandleAdd方法。添加按钮通过@click="HandleAdd"绑定点击事件,同样触发HandleAdd方法。

script部分,data函数初始化todoName为空字符串。HandleAdd方法先检查todoName是否为空,若为空则弹出提示,阻止后续操作。若有输入内容,则通过this.$emit('add', this.todoName)触发名为add的自定义事件,并将todoName的值作为参数传递给父组件,随后清空todoName,方便用户输入下一个任务。

父组件:接收数据与添加任务

父组件代码如下:

<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader @add="handleadd" ></TodoHeader>
    <TodoMain :list="list"></TodoMain>
    <TodoFooter></TodoFooter>
  </section>
</template>

<script>
import TodoFooter from './components/TodoFooter.vue';
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';

export default {
  data () {
    return {
      list: [
        { id: 1, name: '打篮球' },
        { id: 2, name: '看电影' },
        { id: 3, name: '逛街' },
      ],
    }
  },

  components : {
    TodoHeader,
    TodoMain,
    TodoFooter
  },

  methods: {
    handleadd (todoName) {
      this.list.unshift({
        id : +new Date(),
        name : todoName
      })
    }
  },
}
</script>

在模板中,<TodoHeader>标签通过@add="handleadd"监听TodoHeader组件触发的add事件,事件触发时调用父组件的handleadd方法,并将TodoHeader组件传递的任务名称作为参数传入。

script部分,handleadd方法接收子组件传来的todoName,通过unshift方法将新任务添加到list数组开头。新任务对象包含一个由当前时间戳生成的唯一id和接收到的todoName

通过父子组件的紧密协作,小黑记事本的添加任务功能得以顺利实现。用户输入任务名称,点击按钮或按回车键,任务便会快速添加到任务列表顶部。这一功能不仅展示了Vue组件通信与数据处理的便捷性,也为构建复杂交互应用提供了基础思路。在实际开发中,我们可以基于此功能进一步拓展,如添加任务验证规则、优化提示信息,使应用更加完善,为用户带来更好的体验。

4、删除任务

监听删除操作并携带id,子传父传递id,父组件利用filter方法删除对应任务。通过删除任务这个功能,用户可以灵活管理自己的任务列表,删除不再需要的任务。下面我们来详细讲解该功能是如何通过Vue实现的,其核心流程为监听删除操作并携带任务id,子组件将id传递给父组件,父组件利用filter方法删除对应任务。

功能实现的组件架构

小黑记事本应用由多个组件协同工作,其中TodoMain组件负责展示任务列表,并且提供删除任务的交互操作;TodoMain组件作为子组件,将用户的删除操作传递给父组件;父组件负责实际的任务数据管理,接收到删除指令后执行删除操作。在父组件中,相关代码如下:

<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader @add="handleadd"></TodoHeader>
    <TodoMain @del="handleDel" :list="list"></TodoMain>
    <TodoFooter></TodoFooter>
  </section>
</template>

<script>
import TodoFooter from './components/TodoFooter.vue';
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';

export default {
  data() {
    return {
      list: [
        { id: 1, name: '打篮球' },
        { id: 2, name: '看电影' },
        { id: 3, name: '逛街' },
      ],
    };
  },
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter
  },
  methods: {
    handleadd(todoName) {
      this.list.unshift({
        id: +new Date(),
        name: todoName
      });
    },
    handleDel(id) {
      this.list = this.list.filter(item => item.id !== id);
    }
  },
};
</script>

在上述代码中,父组件通过TodoMain标签上的@del="handleDel"监听TodoMain组件触发的del事件,并将触发事件时传递的参数(即任务id)传递给handleDel方法。当handleDel方法被调用时,它使用filter方法创建一个新数组,该数组排除了id与传入参数id相等的任务对象,从而实现删除对应任务的功能。

子组件TodoMain:触发删除事件

TodoMain组件的模板和脚本代码如下:

<template>
  <!-- 列表区域 -->
  <section class="main">
      <ul class="todo-list">
        <li v-for="(item, index) in list" :key="item.id" class="todo">
          <div class="view">
            <span class="index">{{index + 1}}.</span> <label>{{ item.name }}</label>
            <button @click="handleDel(item.id)" class="destroy"></button>
          </div>
        </li>
      </ul>
    </section>
</template>

<script>
export default {
    props: {
        list : Array
    },
    methods: {
      handleDel(id) {
        this.$emit('del', id);
      }
    },
};
</script>

在模板中,每个任务列表项都包含一个删除按钮,通过@click="handleDel(item.id)"绑定点击事件,当用户点击删除按钮时,会触发handleDel方法,并将当前任务的id作为参数传入。在script部分的handleDel方法中,通过this.$emit('del', id)触发del事件,并将任务id传递给父组件。这样,父组件就能接收到要删除的任务id,并执行相应的删除操作。

通过以上父子组件的配合,小黑记事本的删除任务功能得以顺利实现。当用户点击任务列表中的删除按钮时,TodoMain组件会将对应的任务id传递给父组件,父组件则利用filter方法从任务列表中删除该任务。这一功能的实现,充分展示了Vue组件之间高效的数据通信和灵活的交互能力。在实际开发中,我们可以根据需求进一步优化该功能,比如添加删除确认提示框,防止用户误删任务,提升用户体验。

5、底部合计和清空功能

底部合计通过父传子传递list实现展示;清空功能由子传父通知父组件,父组件执行清空操作。

在小黑记事本的开发过程中,底部合计和清空功能以及数据持久化存储是提升用户体验和数据管理的关键部分。这两个功能的实现,不仅让用户能直观了解任务数量并便捷管理任务列表,还确保数据在页面刷新或关闭后依然存在。下面我们就来详细探讨这两个功能的实现思路与代码逻辑。

底部合计功能:父传子实现数据展示

小黑记事本的底部区域由TodoFooter组件负责呈现,它需要展示任务的合计数量。而任务数据存储在父组件中,因此需要通过父传子的方式将任务列表list传递给TodoFooter组件。

  1. 父组件传递数据:在父组件中,代码如下:
<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader @add="handleadd"></TodoHeader>
    <TodoMain @del="handleDel" :list="list"></TodoMain>
    <TodoFooter @clear="handleClear" :list="list"></TodoFooter>
  </section>
</template>

<script>
import TodoFooter from './components/TodoFooter.vue';
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';

export default {
  data() {
    return {
      list: JSON.parse(localStorage.getItem('list')) || [
        { id: 1, name: '打篮球' },
        { id: 2, name: '看电影' },
        { id: 3, name: '逛街' },
      ],
    };
  },
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter
  },
  methods: {
    handleadd(todoName) {
      this.list.unshift({
        id: +new Date(),
        name: todoName
      });
    },
    handleDel(id) {
      this.list = this.list.filter(item => item.id !== id);
    },
    handleClear() {
      this.list = [];
    }
  },
  watch: {
    list: {
      deep: true,
      handler(newValue) {
        localStorage.setItem('list', JSON.stringify(newValue));
      }
    }
  },
};
</script>

在父组件的模板中,通过TodoFooter标签上的:list="list",将父组件中的list数据传递给TodoFooter组件。这样,TodoFooter组件就能获取到任务列表,从而进行底部合计数量的计算和展示。
2. 子组件展示数据TodoFooter组件代码如下:

<template>
  <!-- 统计和清空 -->
  <footer class="footer">
      <!-- 统计 -->
      <span class="todo-count">合 计:<strong> {{list.length}} </strong></span>
      <!-- 清空 -->
      <button @click="clear" class="clear-completed">
        清空任务
      </button>
    </footer>
</template>

<script>
export default {
    props: {
        list: Array
    },
    methods: {
        clear() {
            this.$emit('clear');
        }
    },
};
</script>

TodoFooter组件中,通过props接收父组件传递过来的list。在模板中,使用{{list.length}}直接展示任务列表的长度,也就是任务的合计数量。每当任务列表发生变化,父组件传递的list更新,TodoFooter组件中的合计数量也会实时更新,为用户提供最新的任务统计信息。

清空功能:子传父触发清空操作

清空功能允许用户一键删除所有任务,这需要子组件TodoFooter触发事件通知父组件执行清空任务列表的操作。

  1. 子组件触发事件:在TodoFooter组件中,当用户点击“清空任务”按钮时,会触发clear方法。代码如下:
<template>
  <!-- 统计和清空 -->
  <footer class="footer">
      <!-- 统计 -->
      <span class="todo-count">合 计:<strong> {{list.length}} </strong></span>
      <!-- 清空 -->
      <button @click="clear" class="clear-completed">
        清空任务
      </button>
    </footer>
</template>

<script>
export default {
    props: {
        list: Array
    },
    methods: {
        clear() {
            this.$emit('clear');
        }
    },
};
</script>

clear方法通过this.$emit('clear')触发一个名为clear的自定义事件,该事件会向上传递给父组件。
2. 父组件执行清空:父组件监听TodoFooter组件触发的clear事件,并执行相应的清空操作。在父组件中:

<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader @add="handleadd"></TodoHeader>
    <TodoMain @del="handleDel" :list="list"></TodoMain>
    <TodoFooter @clear="handleClear" :list="list"></TodoFooter>
  </section>
</template>

<script>
import TodoFooter from './components/TodoFooter.vue';
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';

export default {
  data() {
    return {
      list: JSON.parse(localStorage.getItem('list')) || [
        { id: 1, name: '打篮球' },
        { id: 2, name: '看电影' },
        { id: 3, name: '逛街' },
      ],
    };
  },
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter
  },
  methods: {
    handleadd(todoName) {
      this.list.unshift({
        id: +new Date(),
        name: todoName
      });
    },
    handleDel(id) {
      this.list = this.list.filter(item => item.id !== id);
    },
    handleClear() {
      this.list = [];
    }
  },
  watch: {
    list: {
      deep: true,
      handler(newValue) {
        localStorage.setItem('list', JSON.stringify(newValue));
      }
    }
  },
};
</script>

在父组件的模板中,TodoFooter标签上的@clear="handleClear"监听clear事件,当事件触发时,会调用父组件的handleClear方法。在handleClear方法中,通过this.list = []将任务列表清空,实现了清空所有任务的功能。

6、持久化存储

持久化存储:使用watch监视数据变化

为了保证任务数据在页面刷新或关闭后不会丢失,我们使用watch来监视任务列表list的变化,并将数据持久化存储到本地。在父组件中:

<script>
import TodoFooter from './components/TodoFooter.vue';
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';

export default {
  data() {
    return {
      list: JSON.parse(localStorage.getItem('list')) || [
        { id: 1, name: '打篮球' },
        { id: 2, name: '看电影' },
        { id: 3, name: '逛街' },
      ],
    };
  },
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter
  },
  methods: {
    handleadd(todoName) {
      this.list.unshift({
        id: +new Date(),
        name: todoName
      });
    },
    handleDel(id) {
      this.list = this.list.filter(item => item.id !== id);
    },
    handleClear() {
      this.list = [];
    }
  },
  watch: {
    list: {
      deep: true,
      handler(newValue) {
        localStorage.setItem('list', JSON.stringify(newValue));
      }
    }
  },
};
</script>

通过watch监听list的变化,当list发生改变时,handler函数会被触发。在handler函数中,使用localStorage.setItem('list', JSON.stringify(newValue))将更新后的任务列表存储到本地。JSON.stringify方法将任务列表转换为JSON字符串进行存储,在页面加载时,通过JSON.parse(localStorage.getItem('list'))从本地获取数据并转换为数组,赋值给list,从而实现数据的持久化。

通过底部合计、清空功能以及持久化存储的实现,小黑记事本在功能完整性和用户体验上都得到了极大的提升。这些功能的实现,不仅加深了我们对Vue组件通信和数据管理的理解,也为开发更加复杂的应用奠定了坚实的基础。在实际项目中,我们可以根据需求进一步扩展和优化这些功能,例如添加动画效果、优化存储逻辑等,为用户打造更优质的应用体验。

7、总结

image-20250116105837793

四、进阶语法

  1. v-model原理及应用v-model本质是语法糖,在输入框上是value属性和input事件的合写,实现数据双向绑定。在表单类组件封装中,可通过拆解v-model实现子组件和父组件数据双向绑定。父组件传递prop数据,子组件监听输入并传值给父组件修改。简化代码时,子组件通过value接收props,触发input事件;父组件直接用v-model绑定数据。示例如下:
    子组件BaseSelect.vue
<template>
  <select :value="value" @change="handleChange">
    <!-- 选项 -->
  </select>
</template>
<script>
  export default {
    props: {
      value: String
    },
    methods: {
      handleChange (e) {
        this.$emit('input', e.target.value)
      }
    }
  }
</script>

父组件使用:

<BaseSelect v-model="selectId"></BaseSelect>
  1. .sync修饰符:可实现子组件与父组件数据双向绑定,且prop属性名可自定义。其本质是:属性名@update:属性名的合写,常用于封装弹框类基础组件。例如:
    父组件:
<BaseDialog :visible.sync="isShow" />

等同于:

<BaseDialog :visible="isShow" @update:visible="isShow = $event" />

子组件:

props: {
  visible: Boolean
},
methods: {
  closeDialog() {
    this.$emit('update:visible', false)
  }
}
  1. **ref和 r e f s ∗ ∗ :用于获取 D O M 元素或组件实例,查找范围为当前组件内,相比 ‘ d o c u m e n t . q u e r y S e l e c t o r ‘ 更精确稳定。获取 D O M 元素时,给目标标签添加 ‘ r e f ‘ 属性,在合适时机通过 ‘ t h i s . refs**:用于获取DOM元素或组件实例,查找范围为当前组件内,相比`document.querySelector`更精确稳定。获取DOM元素时,给目标标签添加`ref`属性,在合适时机通过`this. refs:用于获取DOM元素或组件实例,查找范围为当前组件内,相比document.querySelector更精确稳定。获取DOM元素时,给目标标签添加ref属性,在合适时机通过this.refs.xxx获取。获取组件实例同理,给目标组件添加ref`属性后,可调用组件对象的方法。例如:
    获取DOM元素:
<template>
  <div ref="chartRef">我是渲染图表的容器</div>
</template>
<script>
  export default {
    mounted () {
      console.log(this.$refs.chartRef)
    }
  }
</script>

获取组件实例:

<template>
  <BaseForm ref="baseForm"></BaseForm>
</template>
<script>
  export default {
    methods: {
      handleSubmit() {
        this.$refs.baseForm.resetForm() 
      }
    }
  }
</script>
  1. ** n e x t T i c k ∗ ∗ :由于 V u e 异步更新 D O M ,在数据更新后立即操作 D O M 可能无法成功。 ‘ nextTick**:由于Vue异步更新DOM,在数据更新后立即操作DOM可能无法成功。` nextTick:由于Vue异步更新DOM,在数据更新后立即操作DOM可能无法成功。nextTick可在DOM更新后执行函数体。例如,编辑标题时,希望编辑框在显示后自动聚焦,可使用$nextTick`:
<template>
  <div>
    <h1 v-if="!isShowEdit">{{title}}</h1>
    <input v-if="isShowEdit" ref="inp" />
    <button @click="editTitle">编辑</button>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        title: '大标题',
        isShowEdit: false
      }
    },
    methods: {
      editTitle() {
        this.isShowEdit = true 
        this.$nextTick(() => {
          this.$refs.inp.focus() 
        })
      }
    }
  }
</script>

通过今天的学习,对Vue组件开发有了更深入的理解,组件通信和进阶语法为构建复杂应用提供了强大工具。在实际项目中,应根据具体场景选择合适的方法,不断优化代码结构和性能。


http://www.kler.cn/a/509886.html

相关文章:

  • Android系统开发(八):从麦克风到扬声器,音频HAL框架的奇妙之旅
  • 【ESP32】ESP-IDF开发 | WiFi开发 | AP模式 + 基站连接例程
  • Python根据图片生成学生excel成绩表
  • HTML5 Canvas实现的跨年烟花源代码
  • python如何解析word文件格式(.docx)
  • RPA编程实践:Electron简介
  • 大华C++开发面试题及参考答案
  • opencv对直方图的计算和绘制
  • 网络安全行业岗位职责
  • SSM旅游信息管理系统
  • ros 机器人地图转化为gis地图
  • DNS未响应服务问题的解决(电脑连着网但浏览器访问不了网页)
  • C#高级:通过 Assembly 类加载 DLL 和直接引用DLL的方法大全
  • Chromium 132 编译指南 Linux 篇 - 同步第三方库以及 Hooks(六)
  • Python:两数之和
  • 当使用 npm 时,出现 `certificate has expired` 错误通常意味着请求的证书已过期。
  • 【机器学习:二十九、K-means算法:原理与应用】
  • SVM模型(理论知识2)
  • 【C++】如何从源代码编译红色警戒2地图编辑器
  • npm操作大全:从入门到精通
  • QMS检测设备日志采集工具
  • 计算机网络滑动窗口三种协议全解析:原理和应用!!!
  • “AI智慧化服务系统:未来生活的智能管家
  • 数据可视化:让数据讲故事的艺术
  • PostgreSQL版本选择
  • VUE3 Vue Router 是官方的路由管理工具