Skip to content

Custom Directives

Giới Thiệu

Ngoài bộ các chỉ thị mặc định được gửi kèm trong core (như v-model hoặc v-show), Vue cũng cho phép bạn đăng ký các chỉ thị tùy chỉnh của riêng bạn.

Chúng tôi đã giới thiệu hai hình thức tái sử dụng mã trong Vue: componentscomposables. Components là các khối xây dựng chính, trong khi composables tập trung vào việc tái sử dụng logic có trạng thái. Ngược lại, các chỉ thị tùy chỉnh chủ yếu được thiết kế để tái sử dụng logic liên quan đến việc truy cập DOM cấp thấp trên các phần tử đơn giản.

Một chỉ thị tùy chỉnh được định nghĩa như một đối tượng chứa các hooks vòng đời tương tự như của một component. Các hooks nhận phần tử mà chỉ thị được ràng buộc. Dưới đây là một ví dụ về một chỉ thị đặc biệt để tập trung vào một ô nhập khi phần tử được chèn vào DOM bởi Vue:

vue
<script setup>
// kích hoạt v-focus trong các mẫu
const vFocus = {
  mounted: (el) => el.focus()
}
</script>

<template>
  <input v-focus />
</template>
js
const focus = {
  mounted: (el) => el.focus()
}

export default {
  directives: {
    // kích hoạt v-focus trong mẫu
    focus
  }
}
template
<input v-focus />

Giả sử bạn chưa nhấp chuột nơi nào khác trên trang, ô nhập ở trên nên được tập trung tự động. Chỉ thị này hữu ích hơn so với thuộc tính autofocus vì nó không chỉ hoạt động khi trang được tải - nó cũng hoạt động khi phần tử được chèn động bởi Vue.

Trong <script setup>, bất kỳ biến nào viết liền bắt đầu bằng tiền tố v có thể được sử dụng như một chỉ thị tùy chỉnh. Trong ví dụ trên, vFocus có thể được sử dụng trong mẫu như v-focus.

Nếu không sử dụng <script setup>, chỉ thị tùy chỉnh có thể được đăng ký bằng cách sử dụng tùy chọn directives:

js
export default {
  setup() {
    /*...*/
  },
  directives: {
    // kích hoạt v-focus trong mẫu
    focus: {
      /* ... */
    }
  }
}

Tương tự như components, chỉ thị tùy chỉnh phải được đăng ký để chúng có thể được sử dụng trong mẫu. Trong ví dụ trên, chúng tôi sử dụng đăng ký cục bộ thông qua tùy chọn directives.

Thường thấy cũng là việc đăng ký các chỉ thị tùy chỉnh toàn cầu tại cấp ứng dụng:

js
const app = createApp({})

// làm cho v-focus có thể được sử dụng trong tất cả các component
app.directive('focus', {
  /* ... */
})

TIP

Chỉ nên sử dụng chỉ thị tùy chỉnh khi chức năng mong muốn chỉ có thể đạt được thông qua quản lý DOM trực tiếp. Ưu tiên sử dụng templating mô tả bằng các chỉ thị tích hợp sẵn như v-bind khi có thể vì chúng hiệu quả hơn và thân thiện với việc render trên máy chủ.

Các Hook của Chỉ Thị

Một đối tượng định nghĩa chỉ thị có thể cung cấp một số hàm hook (tất cả đều tùy chọn):

js
const myDirective = {
  // được gọi trước khi các thuộc tính của phần tử được ràng buộc
  // hoặc các lắng nghe sự kiện được áp dụng
  created(el, binding, vnode, prevVnode) {
    // xem bên dưới để biết chi tiết về các đối số
  },
  // được gọi ngay trước khi phần tử được chèn vào DOM.
  beforeMount(el, binding, vnode, prevVnode) {},
  // được gọi khi phần tử ràng buộc của nó
  // và tất cả các con của nó được chèn.
  mounted(el, binding, vnode, prevVnode) {},
  // được gọi trước khi phần tử ràng buộc của nó được cập nhật
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // được gọi sau khi phần tử ràng buộc của cha
  // và tất cả các con của nó đã được cập nhật
  updated(el, binding, vnode, prevVnode) {},
  // được gọi trước khi phần tử ràng buộc của cha bị giải ràng buộc
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // được gọi khi phần tử ràng buộc của cha bị giải ràng buộc
  unmounted(el, binding, vnode, prevVnode) {}
}

Đối số của Hook

Các hook của chỉ thị nhận các đối số sau:

  • el: phần tử mà chỉ thị được ràng buộc. Điều này có thể được sử dụng để trực tiếp thao tác DOM.

  • binding: một đối tượng chứa các thuộc tính sau.

    • value: Giá trị được chuyển cho chỉ thị. Ví dụ, trong v-my-directive="1 + 1", giá trị sẽ là 2.
    • oldValue: Giá trị trước đó, chỉ có sẵn trong beforeUpdateupdated. Nó có sẵn dù có hay không giá trị đã thay đổi.
    • arg: Đối số được chuyển cho chỉ thị, nếu có. Ví dụ, trong v-my-directive:foo, đối số sẽ là "foo".
    • modifiers: Một đối tượng chứa các modifier, nếu có. Ví dụ, trong v-my-directive.foo.bar, đối tượng modifier sẽ là { foo: true, bar: true }.
    • instance: Thể hiện của component mà chỉ thị được sử dụng.
    • dir: đối tượng định nghĩa chỉ thị.
  • vnode: VNode cơ bản đại diện cho phần tử được ràng buộc.

  • prevNode: VNode đại diện cho phần tử được ràng buộc từ lần render trước. Chỉ có sẵn trong các hook beforeUpdateupdated.

Như một ví dụ, xem xét việc sử dụng chỉ thị sau:

template
<div v-example:foo.bar="baz">

Đối số binding sẽ là một đối tượng như sau:

js
{
  arg: 'foo',
  modifiers: { bar: true },
  value: /* giá trị của `baz` */,
  oldValue: /* giá trị của `baz` từ cập nhật trước đó */
}

Tương tự như các chỉ thị tích hợp sẵn, các đối số của chỉ thị tùy chỉnh có thể là động. Ví dụ:

template
<div v-example:[arg]="value"></div>

Ở đây, đối số của chỉ thị sẽ được cập nhật một cách phản ứng dựa trên thuộc tính arg trong trạng thái của component chúng ta.

Ghi chú

Ngoại trừ el, bạn nên coi những đối số này như chỉ có thể đọc và không bao giờ được sửa đổi. Nếu bạn cần chia sẻ thông tin giữa các hook, khuyến cáo làm điều đó thông qua dataset của phần tử.

Tự Shorthand

Thường thì một chỉ thị tùy chỉnh có thể có cùng hành vi cho cả mountedupdated, mà không cần các hook khác. Trong những trường hợp như vậy, chúng ta có thể định nghĩa chỉ thị dưới dạng một hàm:

template
<div v-color="color"></div>
js
app.directive('color', (el, binding) => {
  // điều này sẽ được gọi cho cả `mounted` và `updated`
  el.style.color = binding.value
})

Đối Tượng Chữ Nhật

Nếu chỉ thị của bạn cần nhiều giá trị, bạn cũng có thể truyền vào một đối tượng chữ nhật JavaScript. Hãy nhớ rằng chỉ thị có thể nhận bất kỳ biểu thức JavaScript hợp lệ nào.

template
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
js
app.directive('demo', (el, binding) => {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text) // => "hello!"
})

Sử Dụng Trên Các Component

Khi sử dụng trên các component, chỉ thị tùy chỉnh sẽ luôn áp dụng cho nút gốc của một component, tương tự như Thuộc tính chuyển tiếp.

template
<MyComponent v-demo="test" />
template
<!-- template của MyComponent -->

<div> <!-- Chỉ thị v-demo sẽ được áp dụng ở đây -->
  <span>Nội dung component của tôi</span>
</div>

Lưu ý rằng các component có thể có nhiều hơn một nút gốc. Khi áp dụng cho một component có nhiều nút gốc, một chỉ thị sẽ bị bỏ qua và một cảnh báo sẽ được thông báo. Khác với thuộc tính, các chỉ thị không thể được chuyển đến một phần tử khác với v-bind="$attrs". Nói chung, không khuyến khích việc sử dụng chỉ thị tùy chỉnh trên các component.

Custom Directives has loaded