Vue slot 插槽

一、基础

Vue 实现了一套内容分发的 API,将 <slot> 元素作为承载分发内容的出口

它允许你像这样合成组件:

<navigation-link url="/profile">
  Your Profile
</navigation-link>

然后你在 <navigation-link> 的模板中可能会写为:

<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>

当组件渲染的时候,这个 <slot> 元素将会被替换为“Your Profile”。插槽内可以包含任何模板代码,包括 HTML:

<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link>

甚至其它的组件:

<navigation-link url="/profile">
  <!-- 添加一个图标的组件 -->
  <font-awesome-icon name="user"></font-awesome-icon>
  Your Profile
</navigation-link>

如果 <navigation-link> 没有包含一个 <slot> 元素,则任何传入它的内容都会被抛弃。

二、应用(利用插槽实现一个上下滚动分页的功能组件)

在内容高度不确定的情况下,通过滚动条的上下滚动来实现分页

Html:

<template>
    <div class="ScrollView"  @scroll="scrollEvent" ref="ScrollView">
       <!-- 这里可以自定义加载状态 -->

        <slot></slot>
    </div>
</template>

Js:

  //  emit事件的typescript写法
  @Emit()
  private scrollDown() {
     console.info('Emit scrollDown')
  }

  @Emit()
  private scrollUp() {
        console.info('Emit scrollUp')
  }
  private scrollEvent(event: any) {
        const scrollTop = event.target.scrollTop;
        const clientHeight = event.target.clientHeight;
        const scrollHeight = event.target.scrollHeight;

        if (scrollTop + clientHeight >= scrollHeight) {   // 当滚动条到达底部时
            this.scrollDown()   // 在这里可以类比父子组件,向父组件emit一个事件
        } else if(scrollTop === 0) {   // 当滚动条到达顶部时
            this.scrollUp()    // 同底部
        } 
    }

 使用时:

<scroll-view @scroll-down="loadData(true,false)" @scroll-up="loadData(true,true)" :style="
     {height:height-199 + 'px'}" :dataState="dataState">
   <ul class="chataccount_content" id="scrol">
       <li v-for="(item) in chataccounts" :key="item.id" :class="['ChataccountView', 
               {'clickModel': onClickId === item.id}]">
           <chataccount-concern />
       </li>
   </ul>
 </scroll-view>

用法和组件基本一致,唯一的区别就是可以在其中添加内容,添加的内容渲染后替代<slot></slot>的位置

下面就是分页了:

import { MutliPager } from '@/domain/command'   // 引入一个自定义的分页器

const maxSize = 40;  //  定义一个列表内可存放的组最大数据量

private pager: MutliPager = new MutliPager(5,10); // 定义一个分页器,第一个参数代表最大页
     数,第二个代表每页的数量(pageSize)


private loadData(concern: boolean ,up: boolean) {
        const _this = this;
        const params = Object.assign({
            concern,
            nameLike: this.searchInput,
            snsType: this.snsType
        },up?_this.pager.prevPage():_this.pager.nextPage());  //  这里根据传进来的up参数判断页码的加减
        loadChataccounts(params).then((result: any) => {
           
            if (result.success) {
                _this.pager.total = result.data.totalPages
                const data: Chataccount[] = result.data.content;
                if( _this.chataccounts.length > 0) {
                 //  这里做了一步去重操作,如不需要可省略
                    const validData = data.filter((acct) => _this.chataccounts
                        .findIndex((account) => account.id === acct.id) < 0 )
                    if(validData.length > 0 ) {
                         if(up) {
                            _this.unshift(validData)
                        } else {
                            _this.push(validData)
                        }
                       
                    } 
                } else {
                    _this.chataccounts = data
                }
            } else {
                this.$message({
                    message: result.desc,
                    type: 'error'
                });
            }
        })
    }
   //  向上滚动获取数据 unshift 至列表内
   private unshift(validData: Chataccount[]) {
        this.chataccounts.unshift(...validData)  //  这里需要一个个unshift进去,否则会改变原列表的数据结构
        if(this.chataccounts.length > maxSize) {
            this.chataccounts.splice(maxSize,this.chataccounts.length-maxSize)
        }
    }
   //  向上滚动获取数据 push 至列表内
    private push(validData: Chataccount[]) {
        this.chataccounts.push(...validData)   
        if(this.chataccounts.length > maxSize) {
            this.chataccounts.splice(0,this.chataccounts.length-maxSize)
        }
    }

command.js


export class Pager {
  
  public static FIRST_PAGE = new Pager()
  
  public pageNo: number = 0;
  public pageSize: number = 10;

  /** 数据总页数 */
  public total: number = 0

  public next(): Pager {
    this.pageNo++;
    return this
  }

  public go(pageNo: number) {
    this.pageNo = Math.max(0,pageNo)
  }
  
  public prev(): Pager {
    if(this.pageNo > 0 ) {
      this.pageNo--;
    } else {
      this.pageNo = 0
    }
    return this
  }
}


export class MutliPager {

  /** 每页最大数据数量 */
  public pageSize: number = 10;

  /** 数据总页数 */
  public total: number = 0

  /** 最大可缓存的页码数 */
  private maxSize: number

  /** 缓存页中的第一页的index 从0开始计数 */
  private firstPageNo: number = 0

  /** 缓存页中的最后一页的index 从0开始计数 */
  private lastPageNo: number = 0

  /**
   * @param maxSize 最大可缓存的页码数
   */
  constructor(maxSize: number,pageSize: number) {
    this.maxSize = Math.max(1,maxSize)
    this.pageSize = Math.max(1,pageSize)
  }

  /** 向前一页 */
  public prevPage(): Pager {
    this.prev();
    const result = new Pager()
    result.pageNo = this.firstPageNo
    result.pageSize = this.pageSize
    return result
  } 
  
  /** 向后一页 */
  public nextPage(): Pager {
    this.next();
    const result = new Pager()
    result.pageNo = this.lastPageNo
    result.pageSize = this.pageSize
    return result
  } 

  /** 返回顶部是页码置0 */
  public zero(): Pager {
    const result = new Pager()
    result.pageNo = 0
    return result
  }

  public reset(): void {
    this.firstPageNo = 0
    this.lastPageNo = 0
  }
 
  private next() {
    if((this.lastPageNo+1) >= this.total) {
      this.lastPageNo = this.total - 1
      return
    }
    this.lastPageNo ++;
    if(this.lastPageNo - this.firstPageNo >= this.maxSize) {
      this.firstPageNo ++
    }
    console.info('next='+this.lastPageNo)
  }
  private prev() {
    if(this.firstPageNo <= 0) {
      this.firstPageNo = 0
      return
    }
    this. firstPageNo--;
    if(this.lastPageNo - this.firstPageNo >= this.maxSize) {
      this.lastPageNo --
    }
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值