zoukankan      html  css  js  c++  java
  • 玩转vue的slot内容分发

    vue的内容分发非常适合“固定部分+动态部分”的组件的场景,固定部分可以是结构固定,也可以是逻辑固定,比如下拉loading,下拉loading只是中间内容是动态的,而拉到底部都会触发拉取更多内容的操作,因此我们可以把下拉loading做成一个有slot的插件。

    单个Slot

    在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就不像上面单个,需要有个对应关系。

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

    
    //父
    &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,如果有多个,就插多个,比较简单。

    使用场景 “下拉加载更多”的场景在移动端相对来说出现得比较多。我们知道下拉触底都要监听触底事件,触底的操作也相同(去后台拉取数据),分页算法也相同,因此我们会想到把它做成一个组件,重用这些相同的地方,让其他地方可以共用这个组件,从而减少代码量。

    然而,下拉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来进行位置调整。一点愚见,希望对大家有所帮助。

    原文链接:https://my.oschina.net/u/3970421/blog/2993054

  • 相关阅读:
    SharpDeveloeper开发ASP.NET MVC汗流浃背
    暂停更新文章通知
    一步步学习NHibernate(10)——连接查询和子查询(2)
    一步步学习NHibernate(9)——连接查询和子查询(1)
    20165103 2017-2018-2 课程总结
    Android开发学习——UI篇1.0
    团队作业(三):确定分工
    20165103实验三 Java面向对象程序设计
    查漏补缺
    20165103 实验三 Java面向对象程序设计
  • 原文地址:https://www.cnblogs.com/lovellll/p/10230073.html
Copyright © 2011-2022 走看看