玩转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

相关文章
相关标签/搜索