Vue 核心特性详解:计算属性、监听属性与事件交互实战指南

文章目录


文章目录


前言

在 Vue 组件化开发中,"数据高效处理" 与 "组件灵活交互" 是构建稳定可维护应用的核心,而计算属性、监听属性、事件处理器及自定义事件正是解决这些问题的关键特性;但不少开发者初学时易混淆其适用场景、对细节理解不深,进而导致代码问题,因此本文通过 "概念解析 + 代码示例 + 场景对比" 拆解四大特性的逻辑、用法与注意事项,助力读者明确适用场景、掌握对应开发思路,为复杂 Vue 应用开发筑牢基础


一、Vue的计算属性?

Vue的计算属性

  1. vue的介绍:
    Vue 的计算属性(computed)是用于声明式地处理复杂数据计算的属性,依赖于其他响应式数据,当依赖的数据变化时,计算属性会自动重新计算并缓存结果。
  2. 核心特点
  • 依赖追踪:计算属性会依赖于 data 或其他计算属性中的数据,当依赖项变化时,计算属性会自动重新计算。
  • 缓存机制:只有当依赖项发生变化时,才会重新计算;如果依赖项不变,多次访问计算属性会直接返回缓存的结果,避免重复计算(提升性能)。
  • 声明式:用类似属性的方式定义,使用时像普通数据一样直接访问,无需加括号。
  1. 基本用法
dart 复制代码
vue
<template>
  <div>
    <p>原始数据:{{ message }}</p>
    <p>计算后的数据:{{ reversedMessage }}</p> <!-- 直接访问计算属性 -->
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue'
    };
  },
  computed: {
    // 计算属性:反转 message 的字符串
    reversedMessage() {
      // 依赖于 data 中的 message
      return this.message.split('').reverse().join('');
    }
  }
};
</script>
  • 当 message 变化时(比如通过其他操作修改 this.message = 'Hi'),reversedMessage 会自动重新计算并更新视图。
  • 多次访问 this.reversedMessage 时,只要 message 没变,就会直接返回缓存值,不会重复执行 split/reverse/join。
与方法(methods)的区别
计算属性(computed) 方法(methods)
有缓存,依赖项不变则不重新计算 无缓存,每次调用都会重新执行
使用时直接访问({{ prop }}) 使用时需要调用({{ fn() }})

二、vue的监听属性

一、watch
  1. 监听属性:
    Vue 的监听属性(watch) 用于监视响应式数据的变化,当被监视的数据发生改变时,会自动执行指定的回调函数,常用于实现复杂的业务逻辑(如数据变化后的异步操作、多数据联动等)。
  2. 核心作用
    监听指定数据的变化,触发自定义逻辑(比如数据变化后发送请求、更新其他数据、执行动画等)。
  3. 基本用法
dart 复制代码
<template>
  <div>
    <input v-model="message" placeholder="输入内容">
    <p>监听结果:{{ watchResult }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: '',
      watchResult: ''
    };
  },
  // 监听属性配置
  watch: {
    // 监视 data 中的 message 属性
    message(newVal, oldVal) {
      // 当 message 变化时,自动执行此函数
      // newVal:变化后的值;oldVal:变化前的值
      this.watchResult = `内容从 "${oldVal}" 变成了 "${newVal}"`;
    }
  }
};
</script>
  • 当输入框中 message 的值变化时,watch 中的 message 回调会自动执行,更新 watchResult 的内容。
二、深度监听(deep: true)
  1. 如果监视的是对象或数组,默认情况下 watch 只会监听对象的 "引用变化"(如重新赋值),不会监听对象内部属性的变化。此时需要用 deep: true 开启深度监听。
dart 复制代码
<script>
export default {
  data() {
    return {
      user: {
        name: '张三',
        age: 20
      }
    };
  },
  watch: {
    // 监听对象 user 的内部属性变化
    user: {
      handler(newVal, oldVal) {
        console.log('user 内部属性变化了', newVal);
      },
      deep: true // 开启深度监听(监听对象内部所有属性)
    },
    // 也可以直接监听对象的某个具体属性(更高效)
    'user.age'(newVal) {
      console.log('年龄变化为:', newVal);
    }
  }
};
</script>

当 this.user.age = 21 时,两个监听都会触发(推荐直接监听具体属性,性能更好)。

三、立即执行(immediate: true)
  1. 默认情况下,watch 回调在数据第一次变化时才执行。如果需要初始加载时就执行一次,可以用 immediate: true。
dart 复制代码
vue
<script>
export default {
  data() {
    return {
      searchKey: '初始值'
    };
  },
  watch: {
    searchKey: {
      handler(newVal) {
        console.log('执行搜索:', newVal); // 初始时就会执行一次
      },
      immediate: true // 立即执行(组件加载时触发)
    }
  }
};
</script>

计算属性(computed)与监听属性(watch)的区别

特性 监听属性(watch) 计算属性(computed)
主要用途 监听数据变化并执行副作用(如异步请求、日志打印) 根据依赖计算衍生值(同步操作)
缓存机制 无缓存,数据变化就会触发 有缓存,依赖不变则不重新计算
适用场景 适合处理复杂逻辑(如多数据联动、异步操作) 适合简单的衍生值计算(如拼接、过滤)

三、事件处理器

Vue 的事件处理器是用于监听 DOM 事件或自定义事件,并触发对应逻辑的机制,核心是通过 v-on 指令(或简写 @)绑定事件,实现 "用户操作 → 代码执行" 的交互。

一、基础用法(绑定 DOM 事件)

通过 v-on:事件名="处理函数" 或简写 @事件名="处理函数",绑定点击、输入、鼠标移动等 DOM 原生事件。

  1. 直接执行简单逻辑
dart 复制代码
<template>
  <!-- 点击按钮,直接修改数据(适合简单逻辑) -->
  <button @click="count += 1">点击+1</button>
  <p>计数:{{ count }}</p>
</template>

<script>
export default {
  data() {
    return { count: 0 };
  }
};
</script>
  1. 调用方法(适合复杂逻辑)
dart 复制代码
<template>
  <!-- 点击按钮,调用 handleClick 方法 -->
  <button @click="handleClick">点击触发方法</button>
  <input @input="handleInput" placeholder="输入内容">
</template>

<script>
export default {
  methods: {
    // 处理点击事件
    handleClick() {
      alert('按钮被点击了');
    },
    // 处理输入事件(可接收事件对象 event)
    handleInput(event) {
      console.log('输入的内容:', event.target.value);
    }
  }
};
</script>
  1. 传递自定义参数
dart 复制代码
如果需要给事件方法传参,同时保留原生 event 对象,可通过 $event 显式传递。
vue
<template>
  <!-- 传递自定义参数 + 原生 event 对象 -->
  <button @click="handleBtnClick('参数1', $event)">点击传参</button>
</template>

<script>
export default {
  methods: {
    handleBtnClick(param, event) {
      console.log('自定义参数:', param); // 输出 "参数1"
      console.log('事件目标:', event.target); // 输出按钮 DOM 元素
    }
  }
};

</script>
二、事件修饰符(简化 DOM 操作)

Vue 提供事件修饰符,用于快速处理常见的 DOM 事件细节(如阻止默认行为、阻止冒泡),避免在方法中写 event.preventDefault() 这类重复代码。

常用修饰符:

Vue 事件修饰符对照表

修饰符 作用 示例
.prevent 阻止默认事件行为(如表单提交、链接跳转) @submit.prevent
.stop 阻止事件冒泡(防止父元素触发相同事件) @click.stop
.once 事件只触发一次 @click.once
.self 仅当事件目标为元素自身时触发(忽略子元素触发的事件) @click.self
.enter 限定键盘事件仅在按下回车键时触发(其他按键无效) @keyup.enter
.stop.prevent 组合修饰符:同时阻止冒泡和默认行为(顺序可调换) @click.stop.prevent
.capture 使用事件捕获模式(从外到内触发) @click.capture
.passive 提升滚动性能(不与.prevent共用) @scroll.passive

常见组合用法

  • 表单提交拦截@submit.prevent
  • 阻止冒泡的点击事件@click.stop
  • 一次性事件监听@click.once
  • 按键过滤@keyup.enter(回车键)、@keyup.esc(ESC键)

注意:修饰符可串联使用(如@click.stop.prevent),但顺序可能影响结果。

四、自定义事件

一、自定义事件(子传父):3 种绑定方式
  1. 模板直接绑定(最常用)
    核心逻辑:父组件在子组件标签上用@事件名绑定处理方法,子组件通过$emit触发。示例:
    ● 父组件(Parent.vue):vue
dart 复制代码
<template>
  <Child @sendMsg="handleMsg" /> <!-- 绑定自定`在这里插入代码片`义事件sendMsg -->
</template>
<script>
export default {
  methods: {
    handleMsg(msg) { console.log("收到子组件消息:", msg); }
  }
};
</script>

● 子组件(Child.vue):vue

dart 复制代码
<template>
  <button @click="triggerEvent">发送消息</button>
</template>
<script>
export default {
  methods: {
    triggerEvent() { this.$emit("sendMsg", "Hello 父组件"); } // 触发事件并传参
  }
};
</script>

适用场景:事件逻辑固定,无需动态控制绑定 / 解绑。

  1. ref 手动绑定(动态绑定)

核心逻辑:父组件通过ref获取子组件实例,用$on手动绑定事件,可控制绑定时机。示例:

● 父组件(Parent.vue):vue

dart 复制代码
<template>
  <Child ref="childRef" />
  <button @click="bindEvent">绑定事件</button>
</template>
<script>
export default {
  methods: {
    bindEvent() {
      // 手动绑定事件sendNum,点击子组件按钮后触发
      this.$refs.childRef.$on("sendNum", (num) => {
        console.log("收到数字:", num);
      });
    }
  }
};
</script>

● 子组件(Child.vue):vue

dart 复制代码
<template>
  <button @click="triggerNum">发送随机数</button>
</template>
<script>
export default {
  methods: {
    triggerNum() { this.$emit("sendNum", Math.random()); }
  }
};
</script>

适用场景:需延迟绑定(如点击按钮后才开启监听)。

  1. 动态绑定 + 解绑(临时事件)

核心逻辑:用 o n 绑定事件后,通过 on绑定事件后,通过 on绑定事件后,通过off手动解绑,避免内存泄漏。示例:

● 父组件(Parent.vue):vue

dart 复制代码
<template>
  <Child ref="tempChild" />
  <button @click="bind">绑定临时事件</button>
  <button @click="unbind">解绑</button>
</template>
<script>
export default {
  methods: {
    bind() {
      this.$refs.tempChild.$on("tempEvent", this.handleTemp);
    },
    unbind() {
      this.$refs.tempChild.$off("tempEvent", this.handleTemp); // 精准解绑
    },
    handleTemp(data) { console.log("临时事件数据:", data); }
  }
};
</script>

● 子组件(Child.vue):vue

dart 复制代码
<template>
  <button @click="triggerTemp">触发临时事件</button>
</template>
<script>
export default {
  methods: {
    triggerTemp() { this.$emit("tempEvent", "临时数据"); }
  }
};
</script>

适用场景:弹窗等临时组件,需在关闭后解绑事件。

二、props 传递函数(父传子函数,子调用)

核心逻辑:父组件将函数通过 props 传给子组件,子组件直接调用该函数传递数据(本质是 "父传子" 的反向利用)。示例:

● 父组件(Parent.vue):vue

dart 复制代码
<template>
  <Child :onReceive="handleReceive" /> <!-- 传递函数onReceive -->
</template>
<script>
export default {
  methods: {
    handleReceive(data) { console.log("通过props收到:", data); }
  }
};
</script>

● 子组件(Child.vue):vue

dart 复制代码
<template>
  <button @click="callParent">调用父组件函数</button>
</template>
<script>
export default {
  props: { onReceive: Function }, // 接收父组件传递的函数
  methods: {
    callParent() { this.onReceive("通过props传递的数据"); } // 调用函数传参
  }
};
</script>

适用场景:简单的子向父通信,逻辑较直接时使用。

通信方式对比

方式 核心逻辑 通信方向 适用场景 注意事项
模板绑定自定义事件 $emit + 父 @事件名 子→父 固定事件,无需动态控制 无需手动解绑(组件销毁自动失效)
ref 手动绑定事件 $on绑定 + 子 $emit 子→父 需延迟绑定事件 确保 $refs 已获取子组件
动态绑定 + 解绑 $on绑定 + $off解绑 子→父 临时事件,避免内存泄漏 解绑需匹配事件名和处理函数
props 传递函数 父传函数 + 子调用函数传参 子→父 简单通信,逻辑直接 避免过度使用(易混淆 props 用途)

总结

本文围绕 Vue 核心交互与数据处理能力,系统讲解了四大关键特性:计算属性,监听属性,事件处理器,自定义事件。四大特性各有侧重 ------ 计算属性聚焦 "数据衍生",监听属性聚焦 "数据变化后的逻辑",事件处理器聚焦 "用户交互触发",自定义事件聚焦 "组件通信",共同构成 Vue 组件化开发中数据处理与交互的核心能力体系,帮助开发者构建高效、可维护的 Vue 应用

相关推荐
xixixin_17 小时前
【React】为什么移除事件要写在useEffect的return里面?
前端·javascript·react.js
嘗_17 小时前
react 源码2
前端·javascript·react.js
我只会写Bug啊21 小时前
Vue文件预览终极方案:PNG/EXCEL/PDF/DOCX/OFD等10+格式一键渲染,开源即用!
前端·vue.js·pdf·excel·预览
扯蛋4381 天前
LangChain的学习之路( 一 )
前端·langchain·mcp
Mr.Jessy1 天前
Web APIs学习第一天:获取 DOM 对象
开发语言·前端·javascript·学习·html
ConardLi1 天前
Easy Dataset 已经突破 11.5K Star,这次又带来多项功能更新!
前端·javascript·后端
冴羽1 天前
10 个被严重低估的 JS 特性,直接少写 500 行代码
前端·javascript·性能优化
rising start1 天前
四、CSS选择器(续)和三大特性
前端·css
一 乐1 天前
高校后勤报修系统|物业管理|基于SprinBoot+vue的高校后勤报修系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·毕设
爱喝水的小周1 天前
《UniApp 页面配置文件pages.json》
前端·uni-app·json