NextTick là gì hoặc nó làm gì trong VueJs


104

Tôi đọc tài liệu, nhưng tôi không thể hiểu nó. Tôi biết dữ liệu, tính toán, xem, các phương thức làm gì nhưng được nextTick()sử dụng để làm gì trong vuejs?


17
Khái niệm chính cần hiểu là DOM được cập nhật không đồng bộ . Khi bạn thay đổi giá trị trong Vue, thay đổi không được hiển thị ngay lập tức cho DOM. Thay vào đó, Vue xếp hàng một bản cập nhật DOM và sau đó, trong một bộ đếm thời gian, cập nhật DOM. Thông thường, điều này xảy ra quá nhanh nên không tạo ra sự khác biệt, nhưng đôi khi, bạn cần phải cập nhật DOM được kết xuất sau khi Vue đã kết xuất nó, điều này bạn không thể thực hiện ngay lập tức trong một phương pháp vì cập nhật chưa xảy ra. chưa. Trong những trường hợp đó, bạn sẽ sử dụng nextTick. Tài liệu ở đây .
Bert

Bổ sung cho những gì @Bert đã nói trong https://stackoverflow.com/q/47634258/9979046 ở trên, nextTick () sẽ được sử dụng trong Unit Test, khi bạn cần kiểm tra xem một phần tử có tồn tại trong DOM (HTML) hay không, chẳng hạn như nếu bạn nhận được một số thông tin về yêu cầu Axios.
Oscar Alencar

Câu trả lời:


138

nextTick cho phép bạn làm điều gì đó sau khi bạn đã thay đổi dữ liệu và VueJS đã cập nhật DOM dựa trên sự thay đổi dữ liệu của bạn, nhưng trước khi trình duyệt hiển thị những thay đổi đó trên trang.

Thông thường, các nhà phát triển sử dụng hàm setTimeout JavaScript gốc để đạt được hành vi tương tự. Nhưng, sử dụngsetTimeout giao quyền kiểm soát cho trình duyệt trước khi nó trao lại quyền kiểm soát cho bạn thông qua lệnh gọi lại của bạn.

Giả sử bạn đã thay đổi một số dữ liệu. Vue cập nhật DOM dựa trên dữ liệu. Xin lưu ý rằng các thay đổi DOM chưa được trình duyệt hiển thị trên màn hình. Nếu bạn đã sử dụng nextTick, cuộc gọi lại của bạn sẽ được gọi ngay bây giờ. Sau đó, trình duyệt cập nhật trang. Nếu bạn đã sử dụng setTimeout, cuộc gọi lại của bạn sẽ chỉ được gọi ngay bây giờ.

Bạn có thể hình dung hành vi này bằng cách tạo một thành phần nhỏ như sau:

<template>
  <div class="hello">
    {{ msg }}
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
        msg: 'One'
    }
  },
  mounted() {
      this.msg = 'Two';

      this.$nextTick(() => {
          this.msg = 'Three';
      });
  }
}
</script>

Chạy máy chủ cục bộ của bạn. Bạn sẽ thấy thông báo Threeđược hiển thị.

Bây giờ, thay thế của bạn this.$nextTickbằngsetTimeout

setTimeout(() => {
    this.msg = 'Three';
}, 0);

Tải lại trình duyệt. Bạn sẽ thấy Two, trước khi bạn thấy Three.

Kiểm tra trò chơi này để xem nó trực tiếp

Đó là bởi vì, Vue đã cập nhật DOM thành Two, trao quyền kiểm soát cho trình duyệt. Trình duyệt được hiển thị Two. Sau đó, gọi lại cho bạn. Vue đã cập nhật DOM thành Three. Mà trình duyệt lại hiển thị.

Với nextTick. Vue đã cập nhật DOM thành Two. Đã gọi lại cuộc gọi lại của bạn. Vue đã cập nhật DOM thành Three. Sau đó, đã trao quyền kiểm soát cho trình duyệt. Và, trình duyệt hiển thị Three.

Hy vọng nó đã được rõ ràng.

Để hiểu cách Vue thực hiện điều này, bạn cần hiểu khái niệm Vòng lặp sự kiện và các vi nhiệm vụ .

Khi bạn đã hiểu rõ các khái niệm đó (er), hãy kiểm tra mã nguồn cho nextTick .


4
Một điều tôi không hiểu là khi bạn nói, "vue cập nhật dữ liệu" là bạn đang đề cập đến bản cập nhật được thực hiện với ex: this.name = 'foo'hay bạn đang đề cập đến việc đưa các phần tử html vào trang?
hidar

Tôi không thấy ở đâu trong lịch sử câu hỏi này mà anh ấy nói "vue cập nhật dữ liệu" ... Anh ấy nói "Vue cập nhật DOM dựa trên dữ liệu". Có nghĩa là khi bạn đặt dữ liệu qua this.name = 'foo'vue sẽ cập nhật mô hình đối tượng tài liệu để phản ánh những thay đổi được thực hiện đối với dữ liệu dựa trên mẫu và chức năng mà bạn định cấu hình.
ADJenks

23

Nội dung đã được lấy từ Tác giả Adrià Fontcuberta

Tài liệu Vue cho biết:

Vue.nextTick ([gọi lại, ngữ cảnh])

Trì hoãn lệnh gọi lại được thực thi sau chu kỳ cập nhật DOM tiếp theo. Sử dụng nó ngay sau khi bạn đã thay đổi một số dữ liệu để chờ cập nhật DOM.

Hmm ..., nếu lúc đầu cảm thấy đáng sợ, đừng lo lắng, tôi sẽ cố gắng giải thích nó càng đơn giản càng tốt. Nhưng trước tiên, có 2 điều bạn nên biết:

  1. Việc sử dụng nó là không phổ biến. Giống như một trong những thẻ ma thuật bạc đó. Tôi đã viết một số Vueứng dụng và chạy vào nextTick () một hoặc hai lần.

  2. Sẽ dễ hiểu hơn khi bạn đã thấy một số trường hợp sử dụng thực tế. Sau khi bạn có ý tưởng, nỗi sợ hãi sẽ biến mất, và bạn sẽ có một công cụ tiện dụng dưới thắt lưng.

Vậy thì hãy bắt đầu.

Hiểu về $ nextTick

Chúng ta là lập trình viên, phải không? Chúng tôi sẽ sử dụng phương pháp phân chia và chinh phục yêu thích của mình để cố gắng dịch mô tả .nextTick()từng chút một. Nó bắt đầu với:

Trì hoãn cuộc gọi lại

Ok, bây giờ chúng tôi biết nó chấp nhận một cuộc gọi lại. Vì vậy, nó trông như thế này:

Vue.nextTick(function () {
  // do something cool
});

Tuyệt quá. Cuộc gọi lại này được hoãn lại (đây là cách millenials nói là bị trì hoãn) cho đến khi…

chu kỳ cập nhật DOM tiếp theo.

Được chứ. Chúng ta biết rằng Vue thực hiện cập nhật DOM không đồng bộ . Nó có một cách giữ các bản cập nhật này được “lưu trữ” cho đến khi cần áp dụng chúng. Nó tạo ra một hàng đợi các bản cập nhật và xóa nó khi cần thiết. Sau đó, DOM được “vá” và cập nhật lên phiên bản mới nhất.

Gì?

Hãy để tôi thử lại: Hãy tưởng tượng thành phần của bạn làm điều gì đó thực sự cần thiết và thông minh như this.potatoAmount = 3. Vue sẽ không tự động hiển thị lại thành phần (và do đó là DOM). Nó sẽ xếp hàng các sửa đổi cần thiết. Sau đó, trong lần “đánh dấu” tiếp theo (như trong đồng hồ), hàng đợi được xóa và cập nhật được áp dụng. Tada!

Được chứ! Vì vậy, chúng tôi biết rằng chúng tôi có thể sử dụng nextTick()để chuyển một hàm gọi lại được thực thi ngay sau dữ liệu được thiết lập và DOM đã cập nhật.

Như tôi đã nói trước đó… không thường xuyên như vậy. Phương pháp tiếp cận "luồng dữ liệu" thúc đẩy Vue, React và một cái khác của Google, mà tôi sẽ không đề cập đến, khiến nó hầu như không cần thiết. Tuy nhiên, đôi khi chúng ta cần đợi một số phần tử xuất hiện / biến mất / được sửa đổi trong DOM. Đây là lúc nextTick có ích.

Sử dụng nó ngay sau khi bạn đã thay đổi một số dữ liệu để chờ cập nhật DOM.

Chính xác! Đây là phần định nghĩa cuối cùng mà tài liệu Vue cung cấp cho chúng tôi. Bên trong lệnh gọi lại của chúng tôi, DOM đã được cập nhật để chúng tôi có thể tương tác với phiên bản "cập nhật nhất" của nó.

Chứng minh điều đó

Được rồi được rồi. Xem bảng điều khiển và bạn sẽ thấy rằng giá trị dữ liệu của chúng tôi chỉ được cập nhật bên trong lệnh gọi lại của nextTick:

const example = Vue.component('example', {
  template: '<p>{{ message }}</p>',
  data: function () {
    return {
      message: 'not updated'
    }
  },
  mounted () {
    this.message = 'updated'

        console.log(
        'outside nextTick callback:', this.$el.textContent
    ) // => 'not updated'

    this.$nextTick(() => {
      console.log(
        'inside nextTick callback:', this.$el.textContent
      ) // => 'not updated'
    })
  }
})


new Vue({
  el: '#app',
    render: h => h(example)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.10/vue.js"></script>
<div id="app"></div>

Một trường hợp sử dụng

Hãy cố gắng xác định một số trường hợp sử dụng hữu ích cho nextTick.

Hãy tưởng tượng rằng bạn cần thực hiện một số hành động khi một thành phần được gắn kết. NHƯNG! không chỉ thành phần. Bạn cũng cần đợi cho đến khi tất cả các phần tử con của nó được gắn kết và có sẵn trong DOM. Chỉ trích! Hook được gắn của chúng tôi không đảm bảo rằng toàn bộ cây thành phần hiển thị.

Giá như chúng ta có một công cụ để đợi chu kỳ cập nhật DOM tiếp theo…

Hahaa:

mounted() {
  this.$nextTick(() => {
    // The whole view is rendered, so I can safely access or query
    // the DOM. ¯\_(ツ)_/¯
  })
}

Tóm lại

Vì thế: nextTick là một cách thoải mái để thực thi một hàm sau khi dữ liệu đã được thiết lập và DOM đã được cập nhật.

Bạn cần đợi DOM, có thể vì bạn cần thực hiện một số chuyển đổi hoặc bạn cần đợi thư viện bên ngoài tải nội dung của nó? Sau đó sử dụng nextTick.

Một số người cũng sử dụng nextTick trong các bài kiểm tra đơn vị của họ như một cách để đảm bảo rằng dữ liệu đã được cập nhật. Bằng cách này, họ có thể kiểm tra "phiên bản cập nhật" của thành phần.

Vue.nextTick () hoặc vm. $ NextTick ()?

Đừng lo lắng. Cả hai đều (gần như) giống nhau. Vue.nextTick()đề cập đến phương thức API toàn cầu, trong khi vm.$nextTick()là một phương thức phiên bản. Sự khác biệt duy nhất là vm.$nextTickkhông chấp nhận ngữ cảnh làm tham số thứ hai. Nó luôn bị ràng buộc với this(còn được gọi là bản thân instance).

Một phần cuối cùng của sự mát mẻ

Lưu ý rằng nextTicktrả về mộtPromise , vì vậy chúng ta có thể làm đầy đủ async/awaitvà cải thiện ví dụ:

async mounted () {
    this.message = 'updated'
    console.log(this.$el.textContent) // 'not updated'
    await this.$nextTick()
    console.log(this.$el.textContent) // 'updated'
}

2
Chỉ cần thêm Tác giả gốc và liên kết, ở đầu phần giải thích "của bạn".
Renan Cidale

1
Thật là một lời giải thích đáng kinh ngạc! Cảm ơn bạn rất nhiều cho thời gian và nỗ lực của bạn.
Muaath Alhaddad

16

Tiếp theo Tick về cơ bản cho phép bạn chạy một số mã, sau khi vue đã hiển thị lại thành phần khi bạn đã thực hiện một số thay đổi đối với thuộc tính phản ứng (dữ liệu).

// modify data
vm.msg = 'Hello'
// DOM not updated yet
Vue.nextTick(function () {
  // this function is called when vue has re-rendered the component.
})

// usage as a promise (2.1.0+, see note below)
Vue.nextTick()
  .then(function () {
      // this function is called when vue has re-rendered the component.
})

Từ Tài liệu Vue.js:

Trì hoãn lệnh gọi lại được thực thi sau chu kỳ cập nhật DOM tiếp theo. Sử dụng nó ngay sau khi bạn đã thay đổi một số dữ liệu để chờ cập nhật DOM.

Đọc thêm về nó, tại đây .


2
cập nhật nó như thế nào? đây là những gì tôi không cam kết và. nếu tôi cập nhật vm.msg thì dom đã được cập nhật bởi vì có một văn bản mới '' hello" .. vậy làm thế nào tôi có thể cập nhật nó một lần nữa bạn có thể đăng fiddle với một ví dụ pls nhờ?
hidar

được rồi, tôi sẽ chỉnh sửa câu trả lời và tôi sẽ cố gắng giải thích thêm.
Daksh Miglani

@hidar, bạn có thể sử dụng nó trong các tình huống phải cập nhật nhiều lần, nhưng bạn muốn hiển thị rõ ràng lẫn nhau ở các chu kỳ dom khác nhau
Daksh Miglani

Nó không phải để cho phép bạn cập nhật DOM mà là để làm bất cứ điều gì với nó (có thể là cập nhật, đọc thông tin từ nó, v.v.) sau khi nó bị ảnh hưởng / sửa đổi bởi các thay đổi do Vue thực hiện (vì bạn đã thay đổi giá trị thuộc tính phản ứng , Vân vân).
zenw0lf

Đó là một ví dụ để làm cho nó đơn giản hơn.
Daksh Miglani

7

Để đưa ra câu trả lời của Pranshat về sự khác biệt giữa việc sử dụng nextTick và setTimeout, rõ ràng hơn, tôi đã tách câu hỏi của anh ấy: đây

mounted() {    
  this.one = "One";
 
  setTimeout(() => {
    this.two = "Two"
  }, 0);
  
  //this.$nextTick(()=>{
  //this.two = "Two"
  //})}

Bạn có thể thấy trong fiddle rằng khi sử dụng setTimeOut, dữ liệu ban đầu sẽ nhấp nháy rất nhanh sau khi thành phần được gắn kết trước khi điều chỉnh thay đổi. Trong khi đó, khi sử dụng nextTick, dữ liệu sẽ bị tấn công, thay đổi trước khi hiển thị cho trình duyệt. Vì vậy, trình duyệt hiển thị dữ liệu cập nhật mà thậm chí không có bất kỳ kiến ​​thức cũ. Hy vọng rằng rõ ràng hai khái niệm trong một swoop.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.