玩轉vue的slot內容分發

vue的內容分發很是適合「固定部分+動態部分」的組件的場景,固定部分能夠是結構固定,也能夠是邏輯固定,好比下拉loading,下拉loading只是中間內容是動態的,而拉到底部都會觸發拉取更多內容的操做,所以咱們能夠把下拉loading作成一個有slot的插件。前端

單個Slotvue

在children這個標籤裏面放Dom,Vue不會理你,也就是不會顯示,相似React:this.props.children。算法

//父
<children> 
  <span>12345</span>//這邊不會顯示
</children>
 
//子
components: {
  children: {
    template: "<button>爲了明確做用範圍,因此使用button標籤</button>"
  }
}

你須要寫成這樣網絡

children: {
  template: "<button><slot></slot>爲了明確做用範圍,因此使用button標籤</button>"
}

注意這邊 slot 至關於一個坑,等着父組件給填上,這邊 slot 表明的就是上面的 span函數

多個Slot學習

這邊須要加name屬性,說白了,多個Slot就不像上面單個,須要有個對應關係。this

父-> slot="name1" 子-> <slot name="name1"spa

//父
&lt;children&gt; 
  &lt;span slot=&quot;name1&quot;&gt;12345&lt;/span&gt;
&lt;/children&gt;
 
//子
components: {
  children: {
    template: &quot;&lt;button&gt;
            &lt;slot name=&quot;name1&quot;&gt;&lt;/slot&gt;
            button標籤
          &lt;/button&gt;&quot;
  }
}

這邊寫了一個name1,若是有多個,就插多個,比較簡單。.net

使用場景 「下拉加載更多」的場景在移動端相對來講出現得比較多。咱們知道下拉觸底都要監聽觸底事件,觸底的操做也相同(去後臺拉取數據),分頁算法也相同,所以咱們會想到把它作成一個組件,重用這些相同的地方,讓其餘地方能夠共用這個組件,從而減小代碼量。插件

然而,下拉loading並非一個能夠徹底重用的組件,由於列表裏面的內容不一樣,空白頁(沒有內容時)的內容也可能不一樣,若是要作成組件,那麼就要考慮到這方面的「不一樣」,所以咱們想到利用vue的內容分發slot來作。下面是本人在開發的時候作的一個下拉loading,你們能夠參考下。

組件代碼:

&lt;template&gt;
 &lt;div&gt;
  &lt;slot name=&quot;list&quot; v-if=&quot;total &gt; 0&quot;&gt;&lt;/slot&gt;
  &lt;slot name=&quot;empty&quot; v-else&gt;&lt;/slot&gt;
 &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
import Toast from 'lib/xl-toast'
 
import Tool from 'tool/tool'
 
export default {
 data() {
  return {
   page: 1,
   isLoading: false,
   busy: false,
   isFirstLoad: false
  }
 },
 props: {
  pageSize: {
   default: 10 // 每頁展現多少條數據
  },
  total: {
   default: 0 // 總共多少條記錄
  }
 },
 computed: {
  totalPage() {
   return Math.ceil(this.total / this.pageSize)
  }
 },
 created() {
  this.getList()
 },
 mounted() {
  this.addScrollListener()
 },
 methods: {
  addScrollListener() {
   // 添加監聽滾動操做,用到函數防抖
   this.scrollFn = Tool.throttle(this.onScroll, 30, 30)
   document.addEventListener('scroll', this.scrollFn, false)
  },
  getList() {
   // 正在拉取數據或者沒有數據了,則取消滾動監聽
   if(this.isLoading || this.isFirstLoad &amp;&amp; (this.page &gt; this.totalPage)) {
    document.removeEventListener('scroll', this.scrollFn, false)
    return
   }
   this.busy = true
   this.isLoading = true
   // 通知父組件去拉取更多數據
   this.$emit(&quot;getList&quot;, this.page, () =&gt; {
    this.isFirstLoad = true
    this.isLoading = false
    this.page++
   }, () =&gt; {
    Toast.show('網絡錯誤,請稍後重試')
    this.total = 0
    this.isLoading = false
   })
  },
  reset() {
   // 從新拉取數據
   this.page = 1
   this.total = 0
   this.isLoading = false
   this.isFirstLoad = false
   this.addScrollListener()
   this.getList()
  },
  onScroll() {
   // 到底拉取更多數據 
   if(Tool.touchBottom()) {
    this.getList()
   }
  }
 }
}
&lt;/script&gt;

前端全棧學習交流圈:866109386,面向1-3經驗年前端開發人員,幫助突破技術瓶頸,提高思惟能力,羣內有大量PDF可供自取,更有乾貨實戰項目視頻進羣免費領取。

總之,遇到一些有想對比較固定的部分,包括js操做或者結構固定,又有一些動態的部分,咱們應該就應該考慮到使用:組件+slot。

意向不到的slot另類用法

我在作需求的時候,作了一個組件,該組件分爲上下兩個部分,這兩個部分耦合度很高(否則我怎麼把它當成一個組件呢哈哈哈),以下圖所示: 原本C區域是一個組件,而後產品忽然說,須要把這兩個部分分開,把A移到C1的位置,C1移到A的位置(內心感受到憋屈)。

這裏個人第一個想法就是拆開來作成兩個組件,可是問題來了,以前這兩部分的耦合度很高,若是強制把它拆開成兩個組件,那麼這兩個組件之間的交互必然會多不少。好比,C1改變了某個東西會影響到C2,那麼C1須要觸發事件通知父組件,父組件再調用C2的某個方法來更新狀態。這種跨組件之間的通信在組件之間頻繁交互的狀況下,將會是噩夢,而我這邊卻須要頻繁的交互,因此若是把它拆分爲兩個組件,那麼工做量和複雜度將會大大的增長。固然,你能夠想到經過Event Hub的方式來實現兩個組件之間的交互,可是根本問題仍是沒有實質性得獲得解決。

那麼,有什麼方法能夠作到不拆分紅兩個組件又能移動位置的方法呢,答案就是slot。以個人例子爲例,把A和B做爲C的內容分發,原來是這樣的:

&lt;A&gt;&lt;/A&gt;
&lt;B&gt;&lt;/B&gt;
&lt;C&gt;&lt;/C&gt;

改成slot之後是這樣的

&lt;C&gt;
&lt;A slot=&quot;c1&quot;&gt;&lt;/A&gt;
&lt;B slot=&quot;c2&quot;&gt;&lt;/B&gt;
&lt;/C&gt;

這樣就能作到不把C模塊拆分,又能調整位置了,以最小的代價完成需求~~。

總結

vue的slot不只能夠用來內容分發,還能夠用來作位置調整。若是在須要拆分組件來作位置調整,又不想由於拆分耦合度很高的組件,能夠考慮使用slot來進行位置調整。一點愚見,但願對你們有所幫助。

原文連接:http://www.javashuo.com/article/p-ceqxezdm-kr.html

相關文章
相關標籤/搜索