微信小程序slot让组件封装的可扩展性变得更强

191 阅读3分钟

微信小程序文章推荐:

微信小程序必备开发技能总结(不断更新)

微信小程序自定义组件

一、为什么需要slot

在使用组件的时候可以通过自定义属性传给组件数据,组件通过properties 来接收自定义的属性,实现了组件的传值。有些情况我们封装组件的时候,有一部分视图结构是不确定的,需要外界自己定义,这时候通过自定义属性和properties 就行不通了,这就是为什么需要使用slot 的原因,使用slot ,使得组件的部分结构和样式可以由外界定义。

二、单个的slot

这里以一个弹框组件的封装为例, 弹框的内容结构和样式是不确定的,只有弹框的框样式是确定的,这个时候就可以使用slot,具体使用方式如下:

  1. 新建componments -> dialog 文件夹
  2. 选中dialog 右键新建Componpent,填写组件名称dialog 这样我们就新建好了一个组件
  3. 编写dialog.wxml
<!--components/dialog/dialog.wxml-->
<view class="dialog-opacity">
    <view class="dialog">
        <view class="header">
            <text>{{ title }}</text>
            <view class="close" bindtap="close">X</view>
        </view>
        <view class="dialog-content">
            <slot></slot>
        </view>
    </view>
</view>

这里使用了slot 标签给内容占位,内容由外界确定

dialog.js

// components/dialog/dialog.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {
    title: {
        type: Number,
        value: '标题'
    }

  },


  /**
   * 组件的方法列表
   */
  methods: {
    close () {
        this.triggerEvent('close')
    }
  }
})

dialog.wxss

.dialog-opacity {
    width: 100%;
    height: 100%;
    position: fixed;
    left: 0;
    top: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9;
}

.dialog-opacity .dialog {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: calc(90% - 60rpx);
    height: 300rpx;
    padding: 30rpx;
    border-radius: 8rpx;
    background: #fff;
}
.dialog .header {
    display: flex;
    justify-content: space-between;
}
.dialog .dialog-content{
    padding: 30rpx 0;
}

app.json 中将弹框注册为全局组件:

{
  "pages": [
    "pages/index/index",
  ],
  "window": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "Weixin",
    "navigationBarBackgroundColor": "#ffffff"
  },
  "style": "v2",
  "componentFramework": "glass-easel",
  "sitemapLocation": "sitemap.json",
  "lazyCodeLoading": "requiredComponents",
  "usingComponents": {
    "my-dialog": "/components/dialog/dialog"
  }
}

重点: "my-dialog": "/components/dialog/dialog"

index.wxml页面使用

<!--index.wxml-->
<view>
    <my-dialog bind:close="close" wx:if="{{showDialog}}">
        <view>第一段内容</view>
        <view>第二段内容</view>
    </my-dialog>
    <button bindtap="open" type="primary">打开弹框</button>
</view>

在这里我们直接在my-dialog 标签之间写自定义内容,my-dialog组件中的slot 就会接收到

index.js

// index.js

Page({
    data: {
        showDialog: false
    },
    close () {
        this.setData({
            showDialog: false
        })
    },
    open () {
        this.setData({
            showDialog: true
        })
    }
})

这样我们就利用slot 完成了可以自定义内容结构的弹框。

三、多个slot

有时候,我们的组件不止只有一个内容需要自定义结构,有多个内容需要自定义结构,这时候就需要使用多个slot 了。使用多个slot 在上面的单个基础上需要还需要进行3点修改

  • 组件js中的options 选项中添加 multipleSlots: true
  • 使用slot的时候需要在组件里面的slot标签上增加name定义一个slot的名称
  • 在父组件或者页面中使用的时候通过slot属性来确定自定义的结构放在哪个slot标签的位置。

还是以上面的弹框为例,假设现在标题结构也可能不只是一段文案了,可能还有图标和文案,这些标签结构,底部可能有两个按钮或者只有一个按钮,这种情况就可以用多个slot了, 具体使用如下:

dialog.wxml

<!--components/dialog/dialog.wxml-->
<view class="dialog-opacity">
    <view class="dialog">
        <view class="header">
            <slot name="title"></slot>
            <view class="close" bindtap="close">X</view>
        </view>
        <view class="dialog-content">
            <slot name="content"></slot>
        </view>
        <view class="footer">
            <view><slot name="footer"></slot></view>
        </view>
    </view>
</view>

重点:

  • <slot name="title"></slot>
  • <slot name="content"></slot>
  • <slot name="footer"></slot>

dialog.js

// components/dialog/dialog.js
Component({
    options: {
        multipleSlots: true
    },
    /**
     * 组件的属性列表
     */
    properties: {
        title: {
            type: Number,
            value: '标题'
        }

    },


    /**
     * 组件的方法列表
     */
    methods: {
        close() {
            this.triggerEvent('close')
        }
    }
})

重点multipleSlots: true

dialog.wxss

.dialog-opacity {
    width: 100%;
    height: 100%;
    position: fixed;
    left: 0;
    top: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9;
}

.dialog-opacity .dialog {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: calc(90% - 60rpx);
    height: 300rpx;
    padding: 30rpx;
    border-radius: 8rpx;
    background: #fff;
}
.dialog .header {
    display: flex;
    justify-content: space-between;
}
.dialog .dialog-content{
    padding: 30rpx 0;
}
.dialog .footer{
    display: flex;
    justify-content: center;
}

index.wxml

<!--index.wxml-->
<view>
    <my-dialog bind:close="close" wx:if="{{showDialog}}">
        <view
            slot="title"
        >
           <image src="/assets/img/tip.png" class="title-icon"></image>
            标题
        </view>
        <view slot="content">
            <view>第一段内容</view>
            <view>第二段内容</view>
        </view>
        <view slot="footer">
            <button size="mini" bindtap="close">取消</button>
            <button  type="primary" size="mini" bindtap="confirm">确定</button>
        </view>
    </my-dialog>
    <button bindtap="open" type="primary">打开弹框</button>
</view>

重点:

  • slot="title"
  • slot="content"
  • slot="footer"

index.js

// index.js

Page({
    data: {
        showDialog: false
    },
    confirm () {
        console.log('confirm')
        this.setData({
            showDialog: false
        })
    },
    close () {
        this.setData({
            showDialog: false
        })
    },
    open () {
        this.setData({
            showDialog: true
        })
    }
})

index.wxss


.title-icon {
    width: 20px;
    height: 20px;
}

运行效果:

image.png

四、 总结:

本篇介绍了,单个slot 的用法,多个slot的用法,合理的利用slot 可以增强组件的可扩展性。

今天就分享到这里了,感谢收看,如果你对小程序开发感兴趣,可以关注uni-app,小程序知识储备 专栏