Vue 进阶,指令补充 + computed+watch

前面我们掌握了 Vue 的基础指令,今天聚焦指令进阶、计算属性、侦听器这三个核心能力,让你真正学会 Vue 的高效开发方式!

一、指令补充:让基础指令更强大

基础指令能满足简单需求,结合修饰符、样式增强后,能应对更复杂的场景。

1. 指令修饰符:简化逻辑的 "快捷键"

指令修饰符是v-on/v-model等指令的 "扩展功能",能减少methods中的冗余代码。

(1)v-on修饰符

  • .stop:阻止事件冒泡(替代e.stopPropagation()
  • .prevent:阻止默认行为(替代e.preventDefault()
  • .once:事件只触发一次
  • .enter/.esc:按键修饰符(仅触发指定按键的事件)
html 复制代码
<div id="app">
  <!-- .stop:阻止冒泡 -->
  <div @click="parentClick" style="padding: 20px; background: #eee;">
    父元素
    <button @click.stop="childClick">子按钮(点击不触发父事件)</button>
  </div>

  <!-- .prevent:阻止表单提交默认行为 -->
  <form @submit.prevent="handleSubmit">
    <button type="submit">提交(不刷新页面)</button>
  </form>

  <!-- .once:只触发一次 -->
  <button @click.once="sayHi">只点一次有效</button>

  <!-- .enter:回车触发 -->
  <input @keyup.enter="handleEnter" placeholder="按回车触发">
</div>

<script>
new Vue({
  el: '#app',
  methods: {
    parentClick() { alert('父元素被点击') },
    childClick() { alert('子按钮被点击') },
    handleSubmit() { alert('表单提交了') },
    sayHi() { alert('只触发一次') },
    handleEnter() { alert('按了回车') }
  }
})
</script>

(2)v-model修饰符

  • .trim:自动去除输入内容的首尾空格
  • .number:自动将输入转为数字类型
  • .lazy:失去焦点 / 按回车时才同步数据(默认是输入时实时同步)
html 复制代码
<div id="app">
  <!-- .trim:去空格 -->
  <input v-model.trim="username" placeholder="输入后自动去空格">
  <p>用户名:"{{ username }}"</p>

  <!-- .number:转数字 -->
  <input v-model.number="age" type="number" placeholder="输入数字">
  <p>年龄类型:{{ typeof age }}</p> <!-- 输入后是number类型 -->

  <!-- .lazy:失去焦点同步 -->
  <input v-model.lazy="content" placeholder="失去焦点后同步">
  <p>内容:{{ content }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: { username: '', age: '', content: '' }
})
</script>

2. v-bind样式操作增强

v-bind绑定class/style时,支持对象、数组语法,能更灵活地控制样式。

(1)class的数组语法:同时添加多个动态类

html 复制代码
<div id="app">
  <!-- 数组语法:结合固定类和动态类 -->
  <div 
    class="base-class"
    :class="[activeClass, { redClass: isRed }]"
  >
    动态class数组语法
  </div>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    activeClass: 'active', // 固定动态类
    isRed: true // 条件动态类
  }
})
</script>

<style>
.base-class { padding: 10px; }
.active { border: 1px solid #000; }
.redClass { color: red; }
</style>

(2)style的对象语法:更简洁的动态样式

html 复制代码
<div id="app">
  <!-- style对象语法:直接绑定样式对象 -->
  <div :style="boxStyle">动态style对象</div>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    boxStyle: {
      width: '200px',
      height: '100px',
      backgroundColor: 'lightblue',
      fontSize: '16px'
    }
  }
})
</script>

3. v-model适配其他表单元素

v-model不仅支持输入框,还能适配复选框、单选框、下拉选择器等表单元素。

(1)单选框组

html 复制代码
<div id="app">
  <div>选择性别:</div>
  <input type="radio" id="male" value="male" v-model="gender">
  <label for="male">男</label>

  <input type="radio" id="female" value="female" v-model="gender">
  <label for="female">女</label>

  <p>选中:{{ gender }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: { gender: 'male' } // 默认选中男
})
</script>

(2)复选框组

html 复制代码
<div id="app">
  <div>选择爱好:</div>
  <input type="checkbox" id="game" value="game" v-model="hobbies">
  <label for="game">游戏</label>

  <input type="checkbox" id="reading" value="reading" v-model="hobbies">
  <label for="reading">阅读</label>

  <input type="checkbox" id="sports" value="sports" v-model="hobbies">
  <label for="sports">运动</label>

  <p>选中:{{ hobbies }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: { hobbies: ['reading'] } // 默认选中阅读
})
</script>

(3)下拉选择器(单选 / 多选)

html 复制代码
<div id="app">
  <!-- 单选下拉框 -->
  <select v-model="selectedCity">
    <option value="">请选择城市</option>
    <option value="beijing">北京</option>
    <option value="shanghai">上海</option>
  </select>
  <p>选中城市:{{ selectedCity }}</p>

  <!-- 多选下拉框(加multiple属性) -->
  <select v-model="selectedFruits" multiple style="height: 100px;">
    <option value="apple">苹果</option>
    <option value="banana">香蕉</option>
    <option value="orange">橙子</option>
  </select>
  <p>选中水果:{{ selectedFruits }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    selectedCity: 'beijing', // 默认选中北京
    selectedFruits: ['apple'] // 默认选中苹果
  }
})
</script>

二、computed 计算属性:高效处理依赖数据

计算属性是基于data中的数据动态计算出的新数据,会缓存结果(依赖不变时不会重复计算),比methods更高效。

1. 基础语法

html 复制代码
<div id="app">
  <p>商品价格:{{ price }} 元</p>
  <p>购买数量:{{ count }}</p>
  <!-- 计算属性:自动计算总价 -->
  <p>总价:{{ totalPrice }} 元</p>
</div>

<script>
new Vue({
  el: '#app',
  data: { price: 50, count: 2 },
  computed: {
    // 计算属性:函数形式,返回计算结果
    totalPrice() {
      return this.price * this.count;
    }
  }
})
</script>

2. 计算属性 vs 方法:核心区别

  • computed 计算属性:依赖数据不变时,结果会缓存;当作属性使用(不加());依赖数据的动态计算(如总价)
  • methods 方法:每次调用都会重新执行;当作方法调用(加());事件处理、复杂逻辑(无缓存)

3. 完整写法(含 get/set)

计算属性默认是 "只读" 的,若需要修改计算属性,可以用get(读取)和set(修改)的完整写法:

html 复制代码
<div id="app">
  <p>姓:{{ firstName }}</p>
  <p>名:{{ lastName }}</p>
  <p>全名:{{ fullName }}</p>
  <!-- 修改计算属性 -->
  <input v-model="fullName" placeholder="修改全名">
</div>

<script>
new Vue({
  el: '#app',
  data: { firstName: '张', lastName: '三' },
  computed: {
    fullName: {
      // get:读取计算属性时执行
      get() {
        return this.firstName + this.lastName;
      },
      // set:修改计算属性时执行
      set(newValue) {
        // 拆分新值为姓和名
        this.firstName = newValue[0];
        this.lastName = newValue.slice(1);
      }
    }
  }
})
</script>

4. 实战案例:成绩统计

html 复制代码
<div id="app">
  <div>语文:<input v-model.number="chinese"></div>
  <div>数学:<input v-model.number="math"></div>
  <div>英语:<input v-model.number="english"></div>
  <!-- 计算属性:统计总分、平均分 -->
  <p>总分:{{ totalScore }}</p>
  <p>平均分:{{ averageScore }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: { chinese: 80, math: 90, english: 85 },
  computed: {
    totalScore() {
      return this.chinese + this.math + this.english;
    },
    averageScore() {
      return Math.round(this.totalScore / 3); // 四舍五入
    }
  }
})
</script>

三、watch 侦听器:监听数据变化做联动

侦听器用于监听datacomputed中数据的变化,当数据改变时执行自定义逻辑(如请求接口、更新 DOM)。

1. 基础语法

html 复制代码
<div id="app">
  <input v-model="username" placeholder="输入用户名">
</div>

<script>
new Vue({
  el: '#app',
  data: { username: '' },
  watch: {
    // 监听username的变化
    username(newVal, oldVal) {
      console.log(`用户名从${oldVal}变成了${newVal}`);
      // 实际场景:可在这里调用接口检测用户名是否重复
      // this.checkUsername(newVal);
    }
  },
  methods: {
    checkUsername(name) {
      // 模拟接口请求
      console.log(`检测用户名:${name} 是否可用`);
    }
  }
})
</script>

2. 完整写法(深度监听 / 立即执行)

对于对象 / 数组的变化,需要开启deep: true(深度监听);若需要初始时立即执行,可设置immediate: true

html 复制代码
<div id="app">
  <div>用户信息:{{ user.name }},{{ user.age }}岁</div>
  <button @click="user.age++">增加年龄</button>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    user: { name: '张三', age: 20 }
  },
  watch: {
    // 监听对象的变化(需深度监听)
    user: {
      handler(newVal, oldVal) {
        console.log(`年龄从${oldVal.age}变成了${newVal.age}`);
      },
      deep: true, // 深度监听对象内部属性
      immediate: true // 初始时立即执行一次
    }
  }
})
</script>
相关推荐
暮之沧蓝1 小时前
React(18-19)总结
前端·react.js·前端框架
计算机学姐1 小时前
基于Python的旅游数据分析及可视化系统【2026最新】
vue.js·python·数据挖掘·数据分析·django·旅游·推荐算法
HIT_Weston1 小时前
50、【Ubuntu】【Gitlab】拉出内网 Web 服务:http.server 单/多线程分析(二)
前端·ubuntu·gitlab
我太想进步了C~~1 小时前
Prompt Design(提示词工程)入门级了解
前端·人工智能·算法
crary,记忆1 小时前
如何理解 React的UI渲染
前端·react.js·ui·前端框架
苏打水com1 小时前
Day1-3 夯实基础:HTML 语义化 + CSS 布局实战(对标职场 “页面结构搭建” 核心需求)
前端·css·html·js
m0_740043731 小时前
mapState —— Vuex 语法糖
java·前端·javascript·vue.js
哟哟耶耶1 小时前
WebPage-postcss-px-to-viewport前端适配
前端·javascript·postcss
7澄11 小时前
Java Web 底层解析:Servlet 执行流程、Tomcat 工作原理与自定义 Tomcat 实现
java·前端·servlet·tomcat·自定义tomcat·tomcat执行流程·servlet执行流程