Vue的高级特性

修饰符

事件修饰符

在 Vue 中,为了方便处理 DOM 事件,在事件绑定的时候提供了修饰符的概念,它可以实现一些额外的效果。

常用的事件修饰符有以下几种:

  • .stop:阻止事件冒泡(事件冒泡:点击子元素,事件会一级一级冒泡到父元素)

  • .prevent:阻止浏览器默认行为

  • .capture:捕获事件

  • .self:只当事件在该元素本身触发时执行

  • .once:事件只触发一次

  • .passive:告诉浏览器这个事件的默认行为不会被阻止,可以提高页面的滚动性能(在支持 passive 的浏览器上)

<template>
  <div>
    <button @click.stop="stopClick">阻止事件冒泡</button>
    <a href="..." @click.prevent="preventClick">阻止页面跳转</a>
    <div @click.capture="captureClick">捕获事件</div>
    <div @click.self="selfClick">只有点击当前元素才触发事件</div>
    <button @click.once="onceClick">只触发一次点击事件</button>
    <div @touchmove.passive="handleTouchMove">优化手势滑动的性能</div>
  </div>
</template>
<script>
export default {
  methods: {
    stopClick() {
      console.log("阻止事件冒泡");
    },
    preventClick() {
      console.log("阻止页面跳转");
    },
    captureClick() {
      console.log("捕获事件");
    },
    selfClick() {
      console.log("只有点击当前元素才触发事件");
    },
    onceClick() {
      console.log("只触发一次点击事件");
    },
    handleTouchMove() {
      console.log("优化手势滑动的性能");
    },
  },
};
</script>

按键修饰符

在 Vue 中,除了常规的事件修饰符外,还提供了按键修饰符,用于绑定键盘按键事件。通过按键修饰符,可以方便地处理键盘事件的响应。

常用的按键修饰符有以下几种:

  • .enter:监听 enter 键

  • .tab:监听 tab 键

  • .delete:监听 delete 和 backspace 键

  • .esc:监听 esc 键

  • .space:监听空格键

  • .up:监听上箭头键

  • .down:监听下箭头键

  • .left:监听左箭头键

  • .right:监听右箭头键

例如:

<template>
  <div>
    <input @keyup.enter="onEnter">
    <input @keydown.tab.prevent="onTab">
    <input @keyup.delete="onDelete">
    <input @keyup.esc="onEsc">
    <input @keyup.space="onSpace">
    <input @keyup.up="onUp">
    <input @keyup.down="onDown">
    <input @keyup.left="onLeft">
    <input @keyup.right="onRight">
  </div>
</template>
<script>
export default {
  methods: {
    onEnter() {
      console.log("监听 enter 键");
    },
    onTab() {
      console.log("监听 tab 键");
    },
    onDelete() {
      console.log("监听 delete 和 backspace 键");
    },
    onEsc() {
      console.log("监听 esc 键");
    },
    onSpace() {
      console.log("监听空格键");
    },
    onUp() {
      console.log("监听上箭头键");
    },
    onDown() {
      console.log("监听下箭头键");
    },
    onLeft() {
      console.log("监听左箭头键");
    },
    onRight() {
      console.log("监听右箭头键");
    },
  },
};
</script>

如果在 input 中按下 tab 键,实际上会触发浏览器的默认行为,即切换到下一个可聚焦的控件,而不会触发绑定的 keyup.tab 事件。因此,在 input 中绑定 keyup.tab 并不能实现预期的效果。要想监听 tab 键并阻止默认行为,可以尝试使用 keydown.tab 事件以及 .prevent 修饰符

表单修饰符

在 Vue 中,表单修饰符可以方便处理表单的输入和绑定数据。常用的表单修饰符有以下几种:

  • .lazy:将输入内容同步更新到数据模型时,不会立即更新,而是等到元素失去焦点或按下回车键时才更新。

  • .number:将输入内容转换为数字类型。

  • .trim:去掉输入内容首尾的空格。

<template>
  <div>
    <input v-model.lazy="message1">
    <p>{{message1}}</p>
    <input v-model.number="message2">
    <p>{{message2}}</p>
    <input v-model.trim="message3">
    <p>{{message3}}</p>
  </div>
</template>
<script>
export default {
  data() {
    return {
      message1: "",
      message2: 0,
      message3: ""
    };
  },
};
</script>

鼠标按键修饰符

在 Vue 中,鼠标事件修饰符可以处理用户输入的鼠标事件。常用的鼠标事件修饰符有以下几种:

  • .left:监听鼠标左键事件。

  • .right:监听鼠标右键事件。

  • .middle:监听鼠标中键事件。

<template>
  <div>
    <button @click.left="onClickLeft">左键点击</button>
    <button @click.right="onClickRight">右键点击</button>
    <button @click.middle="onClickMiddle">中键点击</button>
  </div>
</template>
<script>
export default {
  methods: {
    onClickLeft() {
      console.log("监听鼠标左键点击");
    },
    onClickRight() {
      console.log("监听鼠标右键点击");
    },
    onClickMiddle() {
      console.log("监听鼠标中键点击");
    },
  },
};
</script>

计算属性 computed

<template>
  <div>
    <p>{{ message }}</p>
    <p>{{ reversedMessage }}</p>
  </div>
</template>
<script>
export default {
  data() {
    return {
      message: "Hello, Vue!",
    };
  },
  computed: {
    reversedMessage() {
      return this.message.split("").reverse().join("");
    },
  },
};
</script>

在这个例子中,我们定义了一个 message 数据属性和一个 reversedMessage 计算属性。reversedMessage 计算属性依赖于 message 数据属性,它会将 message 反转后返回一个新的字符串。当 message 发生变化时,reversedMessage 计算属性会自动更新。

需要注意的是,计算属性只有在其所依赖的数据发生变化时才会重新求值,否则会直接返回之前缓存的结果。这样可以避免不必要的重复计算,提高性能

<template>
  <div>
    <p>原价:{{ originalPrice }}</p>
    <p>折扣:{{ discountPercent }}</p>
    <p>折后价:<input v-model="discountPrice">元</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 100,
      discount: 0.8,
    };
  },
  computed: {
    originalPrice() {
      return this.price;
    },
    discountPercent: {
      get() {
        return this.discount * 100 + '%';
      },
      set(newValue) {
        this.discount = parseFloat(newValue) / 100;
      }
    },
    discountPrice: {
      get() {
        return this.price * this.discount;
      },
      set(newValue) {
        this.discount = parseFloat(newValue) / this.price;
      }
    },
  }
}
</script>

上述代码中,定义了一个对象,包含 3 个属性(pricediscountdiscountPrice)和 2 个计算属性(originalPricediscountPercent)。其中,originalPrice 计算属性的值为 pricediscountPercent 计算属性的值为 discount 的百分比形式(如 80%),可以通过 set 方法修改 discount 的值,以此更新计算结果;discountPrice 计算属性的值为原价(即 price)打折后的价格,可以通过 set 方法修改 discount 的值,以此更新计算结果。

需要注意的是,可写计算属性只能在 set 方法中更新其依赖的数据,并且必须返回一个值。如果不需要更新依赖数据,可以不实现 set 方法。

侦听器-watch

在 Vue.js 中,侦听器(watch)是一种可以监听某个数据变化并执行相应操作的机制。可以通过 watch 选项或 $watch() 方法来定义侦听器,监听数据变化并执行回调函数。

使用 watch 选项定义侦听器时,需要将需要监听的数据作为键,将回调函数作为值,即可实现对该数据的监听。

<template>
  <div>
    <input v-model="firstName">
    <input v-model="lastName">
    <p>{{ fullName }}</p>
  </div>
  <div>
    <p>书名:{{ book.name }}</p>
    <p>作者:{{ book.author }}</p>
    <button @click="changeBook">修改书籍信息</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      firstName: '123',
      lastName: '456',
      fullName: '',
      book: {
        name: 'JavaScript权威指南',
        author: {
          name: 'David Flanagan',
          age: 50,
        },
      },
    };
  },
  watch: {
    firstName(newValue, oldValue) {
      this.fullName = `${newValue} ${this.lastName}`;
    },
    lastName(newValue, oldValue) {
      this.fullName = `${this.firstName} ${newValue}`;
    },
    // watch 选项也支持把键设置成用 . 分隔的路径:
    'book.author': {
      deep: true,
      handler(newValue, oldValue) {
        console.log('author changed', newValue, oldValue);
      },
    },
  },
  methods: {
    changeBook() {
      this.book.author.age++;
    },
  }

}
</script>

watch 默认是浅层的:被侦听的属性,仅在被赋新值时,才会触发回调函数——而嵌套属性的变化不会触发。如果想侦听所有嵌套的变更,你需要深层侦听器

this.$watch()

除了使用 watch 选项外,还可以使用 $watch() 方法。该方法的参数与 watch 选项相同,只不过需要将侦听的对象作为第一个参数传入。例如:

export default {
  data() {
    return {
      firstName: '',
      lastName: '',
      fullName: '',
    };
  },
  mounted() {
    this.$watch('firstName', (newValue, oldValue) => {
      this.fullName = `${newValue} ${this.lastName}`;
    });
    this.$watch('lastName', (newValue, oldValue) => {
      this.fullName = `${this.firstName} ${newValue}`;
    });
  }
}

上述代码中,在 mounted 钩子函数中使用 $watch() 方法定义了两个侦听器,与使用 watch 选项的效果相同。

vue生命周期钩子

在 Vue.js 中,生命周期钩子(Lifecycle Hooks)是一组函数,用于在组件实例化、挂载、更新和销毁等不同阶段执行相应操作。Vue.js 的生命周期钩子可以分为三类:

  1. 创建阶段

    • beforeCreate:实例刚创建时被调用,此时数据观测和事件都未初始化。

    • created:实例创建完成后被调用,此时已经完成数据观测,但尚未挂载到页面上。

  2. 挂载阶段

    • beforeMount:实例挂载前被调用,此时模板已经编译完成,但尚未渲染成 HTML。

    • mounted:实例挂载后被调用,此时模板已经渲染成 HTML,并挂载到页面上。

  3. 更新/销毁阶段

    • beforeUpdate:数据更新前被调用,此时数据已经发生了变化,但尚未重新渲染视图。

    • updated:数据更新后被调用,此时视图已经重新渲染完毕。

    • beforeDestroy:实例销毁前被调用,此时实例仍然可用。

    • destroyed:实例销毁后被调用,此时实例已经被彻底销毁,不能再访问属性和方法。

除了上述基本的生命周期钩子外,Vue.js 还提供了一些其他的扩展钩子函数,用于处理特定的场景,例如:

  • activated / deactivated:keep-alive 组件激活和停用时被调用。

  • errorCaptured:捕获子孙组件的错误。

在实际开发中,生命周期钩子常常用于初始化数据、动态更新页面、清理定时器和监听器等工作。需要注意的是,在使用生命周期钩子时,应该遵循 Vue.js 组件生命周期的规则,避免在不合适的阶段进行不恰当的操作,从而导致意外的问题。