<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          Vue響應式開發,深入理解Vue.js響應式原理

          時間:?2017-11-10閱讀:?1202標簽:?vue

          引子

          本人是Java背景,許多年前剛接觸JavaScript時有點怪怪的,因為它沒有 getters 和 setters。隨著時間的推移,我開始喜歡上這個缺失的特性,因為相比Java大量的 getter 和 setter,它讓代碼更簡潔。例如,我們看看下面的Java代碼:

          class Person{
              String firstName;
              String lastName;
          
              // 這個Demo中省略了一些構造器代碼 :)
          
              public void setFirstName(firstName) {
                  this.firstName = firstName;
              }
          
              public String getFirstName() {
                  return firstName;
              }
          
              public void setLastName(lastName) {
                  this.lastName = lastName;
              }
          
              public String getLastName() {
                  return lastName;
              }
          }
          
          // Create instance
          Person bradPitt = new Person();
          bradPitt.setFirstName("Brad");
          bradPitt.setLastName("Pitt");
          

          JavaScript開發人員永遠不會這樣做,相反他們會這樣:

          var Person = function () {
          
          };
          
          var bradPitt = new Person();
          bradPitt.firstName = 'Brad';
          bradPitt.lastName = 'Pitt';
          

          這要簡潔的多。通常簡潔更好,不是嗎?

          的確如此,但有時我想獲取一些可以被修改的屬性,但我不用知道這些屬性是什么。例如,我們在Java代碼中擴展一個新的方法 getFullName():

          class Person{
              private String firstName;
              private String lastName;
          
              // 這個Demo中省略了一些構造器代碼 :)
          
              public void setFirstName(firstName) {
                  this.firstName = firstName;
              }
          
              public String getFirstName() {
                  return firstName;
              }
          
              public void setLastName(lastName) {
                  this.lastName = lastName;
              }
          
              public String getLastName() {
                  return lastName;
              }
          
              public String getFullName() {
                  return firstName + " " + lastName;
              }
          }
          
          Person bradPitt = new Person();
          bradPitt.setFirstName("Brad");
          bradPitt.setLastName("Pitt");
          
          // Prints 'Brad Pitt'
          System.out.println(bradPitt.getFullName());
          

          在上面例子中, fullName 是一個計算過的屬性,它不是私有屬性,但總能返回正確的結果。

          C# 和隱式的 getter/setters

          我們來看看 C# 特性之一:隱式的 getters/setters,我真的很喜歡它。在 C# 中,如果需要,你可以定義 getters/setters,但是并不用這樣做,但是如果你決定要這么做,調用者就不必調用函數。調用者只需要直接訪問屬性,getter/setter 會自動在鉤子函數中運行:

          public class Foo {
              public string FirstName {get; set;}
              public string LastName {get; set;}
              public string FullName {get { return firstName + " " + lastName }; private set;}
          }
          

          我覺得這很酷...

          現在,如果我想在JavaScript中實現類似的功能,我會浪費很多時間,比如:

          var person0 = {
              firstName: 'Bruce',
              lastName: 'Willis',
              fullName: 'Bruce Willis',
              setFirstName: function (firstName) {
                  this.firstName = firstName;
                  this.fullName = `${this.firstName} ${this.lastName}`;
              },
              setLastname: function (lastName) {
                  this.lastName = lastName;
                  this.fullName = `${this.firstName} ${this.lastName}`;
              },
          };
          console.log(person0.fullName);
          person0.setFirstName('Peter');
          console.log(person0.fullName);
          

          它會打印出:

          "Bruce Willis"
          "Peter Willis"
          

          但使用 setXXX(value) 的方式并不夠'JavaScripty'(是個玩笑啦)。

          下面的方式可以解決這個問題:

          var person1 = {
              firstName: 'Brad',
              lastName: 'Pitt',
              getFullName: function () {
                  return `${this.firstName} ${this.lastName}`;
              },
          };
          console.log(person1.getFullName()); // 打印 "Brad Pitt"
          

          現在我們回到被計算過的 getter。你可以設置 first 或 last name,并簡單的合并它們的值:

          person1.firstName = 'Peter'
          person1.getFullName(); // 返回 "Peter Pitt"
          

          這的確更方便,但我還是不喜歡它,因為我們要定義一個叫getxxx()的方法,這也不夠'JavaScripty'。許多年來,我一直在思考如何更好的使用 JavaScript。

          然后 Vue 出現了

          在我的Youtube頻道,很多和Vue教程有關的視頻都講到,我習慣響應式開發,在更早的Angular1時代,我們叫它:數據綁定(Data Binding)。它看起來很簡單。你只需要在Vue實例的 data() 塊中定義一些數據,并綁定到HTML:

          var vm = new Vue({
              data() {
                  return {
                  greeting: 'Hello world!',
                  };
              }
          })
          <div>{greeting}</div>
          

          顯然它會在用戶界面打印出 “Hello world!”。

          現在,如果你改變greeting的值,Vue引擎會對此作出反應并相應地更新視圖。

          methods: {
              onSomethingClicked() {
                  this.greeting = "What's up";
              },
          }
          

          很長一段時間我都在想,它是如何工作的?當某個對象的屬性發生變化時會觸發某個事件?或者Vue不停的調用 setInterval 去檢查是否更新?

          通過閱讀Vue官方文檔,我才知道,改變一個對象屬性將隱式調用getter/setter,再次通知觀察者,然后觸發重新渲染,如下圖,這個例子來自官方的Vue.js文檔:


          但我還想知道:

          • 怎么讓數據自帶getter/setters?
          • 這些隱式調用內部是怎樣的?

          第一個問題很簡單:Vue為我們準備好了一切。當你添加新數據,Vue將會通過其屬性為其添加 getter/setters。但是我讓 foo.bar = 3? 會發生什么?

          這個問題的答案出現在我和SVG & Vue專家Sarah Drasner的Twitter對話中:


          Timo: foo.bar=value;是怎么做到實時響應的?

          Sarah: 這個問題很難在Twitter說清楚,可以看這篇文章

          Timo: 但這篇文章并沒有解釋上面提到的問題。

          Timo: 它們就像:分配一個值->調用setter->通知觀察者,不理解為什么在不使用setInterval和Event的情況下,setter/getter就存在了。

          Sarah: 我的理解是:你獲取的所有數據都在Vue實例data{}中被代理了。

          顯然,她也是參考的官方文檔,之前我也讀過,所以我開始閱讀Vue源碼,以便更好的理解發生了什么。過了一會我想起在官方文檔看到一個叫 Object.defineProperty() 的方法,我找到它,如下:

          /**
          * 給對象定義響應的屬性
          */
          export function defineReactive (
              obj: Object,
              key: string,
              val: any,
              customSetter?: ?Function,
              shallow?: boolean
          ) {
              const dep = new Dep()
          
              const property = Object.getOwnPropertyDescriptor(obj, key)
              if (property && property.configurable === false) {
                  return
              }
          
              // 預定義getter/setters
              const getter = property && property.get
              const setter = property && property.set
          
              let childOb = !shallow && observe(val)
              Object.defineProperty(obj, key, {
                  enumerable: true,
                  configurable: true,
                  get: function reactiveGetter () {
                      const value = getter ? getter.call(obj) : val
                      if (Dep.target) {
                          dep.depend()
                          if (childOb) {
                              childOb.dep.depend()
                          }
                          if (Array.isArray(value)) {
                              dependArray(value)
                          }
                      }
                      return value
                  },
                  set: function reactiveSetter (newVal) {
                      const value = getter ? getter.call(obj) : val
                      /* 禁用eslint 不進行自我比較 */
                      if (newVal === value || (newVal !== newVal && value !== value)) {
                          return
                      }
                      /* 開啟eslint 不進行自己比較 */
                      if (process.env.NODE_ENV !== 'production' && customSetter) {
                          customSetter()
                      }
                      if (setter) {
                          setter.call(obj, newVal)
                      } else {
                          val = newVal
                      }
                      childOb = !shallow && observe(newVal)
                      dep.notify()
                  }
              })
          }
          

          所以答案一直存在于文檔中:

          把一個普通 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉為 getter/setter。Object.defineProperty 是僅 ES5 支持,且無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器的原因。

          我只想簡單的了解 Object.defineProperty() 做了什么,所以我用一個例子簡單的給你講解一下:

          var person2 = {
              firstName: 'George',
              lastName: 'Clooney',
          };
          Object.defineProperty(person2, 'fullName', {
              get: function () {
                  return `${this.firstName} ${this.lastName}`;
              },
          });
          console.log(person2.fullName); // 打印 "George Clooney"
          

          還記得文章開頭C#的隱式 getter 嗎?它們看起來很類似,但ES5才開始支持。你需要做的是使用 Object.defineProperty() 定義現有對象,以及何時獲取這個屬性,這個getter被稱為響應式——這實際上就是Vue在你添加新數據時背后所做的事。

          Object.defineProperty()能讓Vue變的更簡化嗎?

          學完這一切,我一直在想,Object.defineProperty() 是否能讓Vue變的更簡化?現今越來越多的新術語,是不是真的有必要把事情變得過于復雜,變的讓初學者難以理解(Redux也是同樣):

          • Mutator:或許你在說(隱式)setter
          • Getters:為什么不用 Object.defineProperty() 替換成(隱式)getter
          • store.commit():為什么不簡化成 foo = bar,而是 store.commit("setFoo", bar);?

          你是怎么認為的?Vuex必須是復雜的還是可以像 Object.defineProperty() 一樣簡單?


          特別聲明,本文轉載@余震翻譯@Rockjins Blog的《Understanding Vue.js Reactivity in Depth with Object.defineProperty()》
          英文地址:https://www.timo-ernst.net/blog/2017/07/26/understanding-vue-js-reactivity-depth-object-defineproperty 
           譯文地址:https://juejin.im/post/59a7b01f6fb9a0249975d39f


          站長推薦

          1.阿里云: 本站目前使用的是阿里云主機,安全/可靠/穩定。點擊領取2000元代金券、了解最新阿里云產品的各種優惠活動點擊進入

          2.騰訊云: 提供云服務器、云數據庫、云存儲、視頻與CDN、域名等服務。騰訊云各類產品的最新活動,優惠券領取點擊進入

          3.廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入

          鏈接: http://www.modern-decoration.com.cn/article/detial/85

          簡單理解vue中的$nextTick

          Vue.nectTick() 是在下次DOM更新循環結束之后執行延遲回調,在修改數據之后使用$nextTick,則可以在回調中獲取更新后的DOM(dom的改變是發生在nextTick()之后),這個方法作用是當數據被修改后使用這個方法

          Vue 的 .sync 修飾符

          .sync 修飾符算是 Vue 的所有修飾符中較難理解的一個,本篇文章就帶你走近 .sync 的世界,深入理解后會發現,其實也就那么回事。修飾符和指令息息相關,下面從 指令 -> 修飾符 -> .sync 修飾符 由淺入深地來講解 .sync 的含義及用法。

          vue中is的作用和用法

          總所周知,ul里面嵌套li的寫法是html語法的固定寫法(還有如table,select等)。my-component是我們自己寫的組件,但是html在渲染dom的時候,my-component對ul來說并不是有效的dom,甚至會報錯。

          一點 Vue.observable 想法

          Vue 2.6.0 新增了 Vue.observable api,但最近才去嘗試使用它。這東西說新也不新,因為他就是 vue 本身的功能,只是暴露出來,成為新 api 了。在老版本中,直接用 new Vue({ data: {} }) 也一樣。

          Vue中props知識點

          如果你一直在閱讀有關\\\"props\\\"內容,你會發現我們可能也一直在使用它們(即使沒有意識到),但也許你并不完全確定它們是什么。或者如何正確使用它們,并充分利用它們。

          12種使用Vue的最佳做法

          隨著 VueJS 的使用越來越廣泛,出現了幾種最佳實踐并逐漸成為標準。在本文中,主要分享在平時開發中一些有用資源和技巧,廢話少說,我們開始吧。

          如何理解vue中的v-bind?

          若不是動態屬性,首先為其增加駝峰化后的監聽,然后再為其增加一個連字符的監聽,例如v-bind:foo-bar.sync,首先v-on:update:fooBar,然后v-on:update:foo-bar。v-on監聽是通過addHandler加上的。

          Vue.use到底是什么?

          我們在使用Vue做項目開發的時候,看到不少輪子都是通過Vue.use來進行使用,感覺甚是高大上。不過Vue.use到底是什么鬼?不妨來看個究竟。

          Vue.js最佳實踐:五招讓你成為Vue.js大師

          本文面向對象是有一定Vue.js編程經驗的開發者。如果有人需要Vue.js入門系列的文章可以在評論區告訴我,有空就給你們寫。對大部分人來說,掌握Vue.js基本的幾個API后就已經能夠正常地開發前端網站

          vue介紹

          庫是一種插件,是一種封裝好的特定方法的集合。提供給開發者使用,控制器在使用者手里。框架是一套架構,會基于自身特定向用戶提供一套相當完整的解決方案,控制權在框架本身

          內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權或違規,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全運營推廣

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网