8 months ago

最近在寫嵌入式聊天頁面,所以會需要輸入文字後自動下拉的功能,後來找到了插件 theomessin大大寫的vue-chat-scroll,這個插件可以做到我剛才的需求,但是後來想要加入上拉到最頂自動觸發加載的功能,之前沒有開發過Vue directive的經驗,決定順手fork增強功能,並打包到npm上。

MutationObserver

在閱讀源碼的同時,有看到一段程式碼

(new MutationObserver(e => {
  let config = binding.value || {};
  let pause = config.always === false && scrolled;
  if (pause || e[e.length - 1].addedNodes.length != 1) return;
  scrollToBottom(el);
})).observe(el, {childList: true, subtree: true});

插件是透過MutationObserver觀察子節點是否有增加,如果有則開始判斷是否需要往下滑;
那就來了解一下MutationObserver的運作機制,在MDN文檔解釋中提到 MutationObserver是用來給開發者呼應(react to) DOM節點的變化,用來取代DOM3加入的 Mutation 事件(depracated)
宣告方式為

let observer = new MutationObserver(
  function callback(MutationRecord, MutationObserver instance)
);

每次MutationObserver的觀察者DOM結構有變化時,就會呼叫callback函式,其中MutationRecord為陣列,每個元素定義的操作在MutationRecord,也就是查看Type(操作的型態)、addedNodes(新增哪些DOM節點)

一開始建立的觀察者observer,也就是MutationObserver的實例,接著就是要操作實例上的方法

/* 建立觀察對象 */
observer.observe(target, config);
/* 取消觀察 */
observer.disconnect();
/* 取得所有觀察到的 MutationRecord */
observer.takeRecords();

廢話不多說,直接上code

關注Attributes

觀察該節點的Attribute,例如class、style、name等DOM屬性值的變化

關注childList
關注characterData

characterData是指節點的文字操作,如appendData()等,需注意要操作characterData必須是TextNode,而不是一般的DOM Node。

Vue Directive

在官網有一篇Custom Directives,在Vue 2.0中程式碼復用與抽象化大多是透過Component,但如果需要底層的DOM 操作就可以客製 Directive,在Directive宣告中,可以自定義名稱,並掛上需要的hook function,這裡僅介紹 bind(僅被呼叫一次,當directive被掛上element時)inserted(當element被插入parent Node的時候呼叫)

Vue.directive('focus', {
  // When the bound element is inserted into the DOM...
  inserted: function (el) {
    // Focus the element
    el.focus()
  }
})

接著看hook function的參數:

  1. el:
    可操作DOM Element,例如 el.style.backgroundColor = "red" / el.focus() 自動focus在input上
  2. binding:
    關於directive設定的相關屬性(name、value、oldValue等等)
    <div v-demo="{ color: 'white', text: 'hello!' }"></div>
    在demo directive中
    binding.value.color -> white
    binding.value.text -> hello
    
  3. vnode:
    由Vue Compiler產生的虛擬Node,文件沒有太多介紹,就直接導向程式碼vnode.js,要在directive觸發事件就必須透過vnode,以下是我找到的答案Vue.js - Emit event from directive
  4. oldValue:
    取得舊的Node值,只有在updatecomponentUpdated hook function有效,這裡略過。

結合以上就可以來修改原本的vue-chat-scroll套件,額外掛上上拉至頂自動觸發加載事件
全部程式碼也就這幾行而已 lol

發布npm

打包至vue-chat-scroll-top-scroll,想不到有人下載了,小小感動了一下XD

← 利用gensim做中文文本相似度比較: 採用Latent Semantic Indexing Swift - 語法初探,筆記 Protocal / Optioanl Value / Enum →
 
comments powered by Disqus