Vue 核心特性详解:计算属性、监听属性与事件交互实战指南
文章目录
文章目录
- 文章目录
- 前言
- 一、Vue的计算属性?
- Vue的计算属性
- 与方法(methods)的区别
- 二、vue的监听属性
- 一、watch
- 二、深度监听(deep: true)
- 三、立即执行(immediate: true)
- 计算属性(computed)与监听属性(watch)的区别
- 三、事件处理器
- 一、基础用法(绑定 DOM 事件)
- 二、事件修饰符(简化 DOM 操作)
- Vue 事件修饰符对照表
- 常见组合用法
- 四、自定义事件
- 一、自定义事件(子传父):3 种绑定方式
- 二、props 传递函数(父传子函数,子调用)
- 通信方式对比
- 总结
前言
在 Vue 组件化开发中,“数据高效处理” 与 “组件灵活交互” 是构建稳定可维护应用的核心,而计算属性、监听属性、事件处理器及自定义事件正是解决这些问题的关键特性;但不少开发者初学时易混淆其适用场景、对细节理解不深,进而导致代码问题,因此本文通过 “概念解析 + 代码示例 + 场景对比” 拆解四大特性的逻辑、用法与注意事项,助力读者明确适用场景、掌握对应开发思路,为复杂 Vue 应用开发筑牢基础
一、Vue的计算属性?
Vue的计算属性
- vue的介绍:
Vue 的计算属性(computed)是用于声明式地处理复杂数据计算的属性,依赖于其他响应式数据,当依赖的数据变化时,计算属性会自动重新计算并缓存结果。 - 核心特点
- 依赖追踪:计算属性会依赖于 data 或其他计算属性中的数据,当依赖项变化时,计算属性会自动重新计算。
- 缓存机制:只有当依赖项发生变化时,才会重新计算;如果依赖项不变,多次访问计算属性会直接返回缓存的结果,避免重复计算(提升性能)。
- 声明式:用类似属性的方式定义,使用时像普通数据一样直接访问,无需加括号。
- 基本用法
vue
<template><div><p>原始数据:{{ message }}</p><p>计算后的数据:{{ reversedMessage }}</p> <!-- 直接访问计算属性 --></div>
</template><script>
export default {data() {return {message: 'Hello Vue'};},computed: {// 计算属性:反转 message 的字符串reversedMessage() {// 依赖于 data 中的 messagereturn this.message.split('').reverse().join('');}}
};
</script>
- 当 message 变化时(比如通过其他操作修改 this.message = ‘Hi’),reversedMessage 会自动重新计算并更新视图。
- 多次访问 this.reversedMessage 时,只要 message 没变,就会直接返回缓存值,不会重复执行 split/reverse/join。
与方法(methods)的区别
计算属性(computed) | 方法(methods) |
---|---|
有缓存,依赖项不变则不重新计算 | 无缓存,每次调用都会重新执行 |
使用时直接访问({{ prop }}) | 使用时需要调用({{ fn() }}) |
二、vue的监听属性
一、watch
- 监听属性:
Vue 的监听属性(watch) 用于监视响应式数据的变化,当被监视的数据发生改变时,会自动执行指定的回调函数,常用于实现复杂的业务逻辑(如数据变化后的异步操作、多数据联动等)。 - 核心作用
监听指定数据的变化,触发自定义逻辑(比如数据变化后发送请求、更新其他数据、执行动画等)。 - 基本用法
<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)
- 如果监视的是对象或数组,默认情况下 watch 只会监听对象的 “引用变化”(如重新赋值),不会监听对象内部属性的变化。此时需要用 deep: true 开启深度监听。
<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)
- 默认情况下,watch 回调在数据第一次变化时才执行。如果需要初始加载时就执行一次,可以用 immediate: true。
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 原生事件。
- 直接执行简单逻辑
<template><!-- 点击按钮,直接修改数据(适合简单逻辑) --><button ="count += 1">点击+1</button><p>计数:{{ count }}</p>
</template><script>
export default {data() {return { count: 0 };}
};
</script>
- 调用方法(适合复杂逻辑)
<template><!-- 点击按钮,调用 handleClick 方法 --><button ="handleClick">点击触发方法</button><input ="handleInput" placeholder="输入内容">
</template><script>
export default {methods: {// 处理点击事件handleClick() {alert('按钮被点击了');},// 处理输入事件(可接收事件对象 event)handleInput(event) {console.log('输入的内容:', event.target.value);}}
};
</script>
- 传递自定义参数
如果需要给事件方法传参,同时保留原生 event 对象,可通过 $event 显式传递。
vue
<template><!-- 传递自定义参数 + 原生 event 对象 --><button ="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 种绑定方式
- 模板直接绑定(最常用)
核心逻辑:父组件在子组件标签上用@事件名绑定处理方法,子组件通过$emit触发。示例:
● 父组件(Parent.vue):vue
<template><Child ="handleMsg" /> <!-- 绑定自定`在这里插入代码片`义事件sendMsg -->
</template>
<script>
export default {methods: {handleMsg(msg) { console.log("收到子组件消息:", msg); }}
};
</script>
● 子组件(Child.vue):vue
<template><button ="triggerEvent">发送消息</button>
</template>
<script>
export default {methods: {triggerEvent() { this.$emit("sendMsg", "Hello 父组件"); } // 触发事件并传参}
};
</script>
适用场景:事件逻辑固定,无需动态控制绑定 / 解绑。
2. ref 手动绑定(动态绑定)
核心逻辑:父组件通过ref获取子组件实例,用$on手动绑定事件,可控制绑定时机。示例:
● 父组件(Parent.vue):vue
<template><Child ref="childRef" /><button ="bindEvent">绑定事件</button>
</template>
<script>
export default {methods: {bindEvent() {// 手动绑定事件sendNum,点击子组件按钮后触发this.$refs.childRef.$on("sendNum", (num) => {console.log("收到数字:", num);});}}
};
</script>
● 子组件(Child.vue):vue
<template><button ="triggerNum">发送随机数</button>
</template>
<script>
export default {methods: {triggerNum() { this.$emit("sendNum", Math.random()); }}
};
</script>
适用场景:需延迟绑定(如点击按钮后才开启监听)。
3. 动态绑定 + 解绑(临时事件)
核心逻辑:用on绑定事件后,通过on绑定事件后,通过on绑定事件后,通过off手动解绑,避免内存泄漏。示例:
● 父组件(Parent.vue):vue
<template><Child ref="tempChild" /><button ="bind">绑定临时事件</button><button ="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
<template><button ="triggerTemp">触发临时事件</button>
</template>
<script>
export default {methods: {triggerTemp() { this.$emit("tempEvent", "临时数据"); }}
};
</script>
适用场景:弹窗等临时组件,需在关闭后解绑事件。
二、props 传递函数(父传子函数,子调用)
核心逻辑:父组件将函数通过 props 传给子组件,子组件直接调用该函数传递数据(本质是 “父传子” 的反向利用)。示例:
● 父组件(Parent.vue):vue
<template><Child :onReceive="handleReceive" /> <!-- 传递函数onReceive -->
</template>
<script>
export default {methods: {handleReceive(data) { console.log("通过props收到:", data); }}
};
</script>
● 子组件(Child.vue):vue
<template><button ="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 应用