微信小程序开发——Vant组件 & 自定义组件

一、Vant Weapp 组件

Vant组件介绍和使用具体参考Vant Weapp官网

1、下载Vant Weapp

步骤(1)npm包初始化

初始化包,自动生成package.json文件。

npm init

步骤(2)通过 npm 安装 Vant Weapp

npm i @vant/weapp -S --production

步骤(3)修改 app.json

将 app.json 中的 "style": "v2" 去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。

步骤(4)构建 npm 包

在详情-本地设置中勾选 使用 npm 模块 选项,并点击 工具 -> 构建 npm,构建完成后,即可引入组件。

构建完成后,会自动生成miniprogram_npm文件夹,表示构建完成。

2、引入组件

在.json文件中配置使用的组件,可以在全局中配置,也可以在单独页面中配置。
在app.json或index.json中引入某个组件。

  "usingComponents": {
    "van-field": "@vant/weapp/field/index"
  },

3、Field 输入框组件

label:输入框左侧文本
value:当前输入的值
type:可设置为任意原生类型, 如 number idcard textarea digit
border:是否显示内边框
readonly:是否只读
title-width:标题宽度
placeholder:输入框为空时占位符
custom-style:自定义样式
autosize:是否自适应内容高度,只对 textarea 有效,可传入对象,如 { maxHeight: 100, minHeight: 50 },单位为px

<van-field label="分类:" title-width="100rpx" model:value="{{ section_name }}" placeholder="请输入分类" border="{{ true }}" readonly bindtap="openpopup" />
<van-field label="答案:" title-width="100rpx" model:value="{{ answer }}" placeholder="请输入答案" border="{{ true }}" type="textarea" autosize custom-style="height:160rpx" />

效果图:

4、Button 按钮组件

type:按钮类型,支持default、primary、info、warning、danger五种类型,默认为default。
size:按钮尺寸,可选值为 normal、large、small、mini,默认为normal。
color:按钮颜色,支持传入linear-gradient渐变色。
custom-style:自定义样式
loading:是否显示为加载状态
loading-text:加载状态提示文字
icon:左侧图标名称或图片链接。可选值参考,支持Icon组件里的所有图标,也可以传入图标 URL。
round:是否为圆形按钮
square:是否为方形按钮
disabled:是否禁用按钮
事件bind:click 点击按钮,且按钮状态不为加载或禁用时触发。使用bindclick 配合loading属性使用,可以实现节流效果。

<van-button icon="plus" type="primary" size="small" bindclick="addSubject" loading="{{isLoading}}" custom-style="width:130rpx" color="#8fb2c9">添加</van-button>

效果图:

5、Popup 弹出层组件

弹出层容器,用于展示弹窗、信息提示等内容,支持多个弹出层叠加展示。
show:是否显示弹出层
position:弹出位置,可选值为top、bottom、right、left。
custom-style:自定义弹出层样式
事件bind:close 关闭弹出层时触发

<van-popup show="{{ isShow }}" bind:close="closepopup" position="bottom">弹出内容</van-popup>

效果图:

6、Picker 选择器组件

columns:对象数组,配置每一列显示的数据
value-key:选项对象中,文字对应的 key。
show-toolbar:是否显示顶部栏
toolbar-position:顶部栏位置,可选值为bottom、top
title:顶部栏标题
loading:是否显示加载状态
defaultIndex:初始选中项的索引,默认为 0
item-height:选项高度
confirm-button-text:确认按钮文字
cancel-button-text:取消按钮文字
事件bind:confirm 点击确认按钮时触发。
事件bind:cancel 点击取消按钮时触发。
事件bind:change 选项改变时触发。

注意:Picker选择器组件必须配合Popup弹出层组件使用,不能单独使用。

<van-popup show="{{ isShow }}" bind:close="closepopup" position="bottom">
    <van-picker show-toolbar columns="{{ columns }}" value-key="Name" bind:cancel="onCancel" bind:confirm="onConfirm" title="请选择分类" defaultIndex="{{activeIndex}}"/>
</van-popup>
Page({
    data: {
        isLoading:false,
        isShow:false,
        activeIndex:0,
        columns: [
            { Name: '杭州' },
            { Name: '宁波' },
            { Name: '温州' },
          ]
    }
})

效果图:

7、CountDown 倒计时组件

time:倒计时时长,单位毫秒
format:时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒,默认为HH:mm:ss
auto-start:是否自动开始倒计时,默认为true
use-slot:是否使用自定义样式插槽,默认为false
timeData 格式:days-剩余天数;hours-剩余小时;minutes-剩余分钟;seconds-剩余秒数;milliseconds-剩余毫秒

<van-count-down use-slot time="{{ time }}" bind:change="onChange">
        <text class="limit">限购</text>
        <text class="red">1杯</text>
        <text class="item">{{ timeData.days }}</text>
        <text class="red">天</text>
        <text class="item">{{ timeData.hours }}</text>
        <text class="red">:</text>
        <text class="item">{{ timeData.minutes }}</text>
        <text class="red">:</text>
        <text class="item">{{ timeData.seconds }}</text>
</van-count-down>
Page({
    data: {
      time: 310 * 67 * 60 * 1000,
      timeData: {},
    },
    onChange(e) {
        let {detail:{days, hours, minutes,seconds}}=e
        this.setData({
          timeData: {
            days:wx.$formatNumber(days), 
            hours:wx.$formatNumber(hours), 
            minutes:wx.$formatNumber(minutes),
            seconds:wx.$formatNumber(seconds)
          }
        });
      },
  })

效果图:

8、Grid 宫格组件

宫格可以在水平方向上把页面分隔成等宽度的区块,用于展示内容或进行页面导航。
column-num:列数
gutter:格子之间的间距,默认单位为px,默认值为0
border:是否显示边框,默认为true
center:是否将格子内容居中显示,默认为true
square:是否将格子固定为正方形,默认为false
direction:格子内容排列的方向,可选值为 horizontal、vertical
use-slot:是否使用自定义内容的插槽。自定义宫格的所有内容,需要设置use-slot属性。

      <van-grid column-num="3" class="goods" border="{{false}}" center="{{false}}">
          <van-grid-item use-slot wx:for="{{coffeedata}}" wx:key="index" class="griditem">
              <image src="{{item.coffeeimg}}" class="goodsimg"></image>
              <view class="goodstitle">{{item.coffeename}}</view>
              <view class="goodstitle">{{item.coffeeprice}}</view>
              <view class="price">
                  <view class="left">
                      <view class="daoshou">到手价<view class="sjx"></view>
                      </view>
                      <view class="money">{{item.coffeenowprice}}</view>
                  </view>
                  <view class="right">
                      <image src="/assets/img/cart.PNG"></image>
                  </view>
              </view>
          </van-grid-item>
      </van-grid>
Page({
    data: {
      coffeedata: [{
          coffeeimg: 'https://img2.baidu.com/it/u=49756185,3106025596&fm=26&fmt=auto',
          coffeename: '厚乳拿铁',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        },
        {
          coffeeimg: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp7.itc.cn%2Fimages01%2F20200729%2Ffd60a84256e5495aba620a0116346bdc.jpeg&refer=http%3A%2F%2Fp7.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639123029&t=779c7275557e3ddcd867b6d909330b36',
          coffeename: '陨石拿铁',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        },
        {
          coffeeimg: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fci.xiaohongshu.com%2F1affff12-dc7f-4319-4180-55a193c443d3%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fci.xiaohongshu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639123114&t=15ec823e0e7d9478c3e4dfd5a51b9384',
          coffeename: '芋泥一起大红袍',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        }, {
          coffeeimg: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg2.doubanio.com%2Fview%2Fgroup_topic%2Fl%2Fpublic%2Fp275163182.jpg&refer=http%3A%2F%2Fimg2.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639123140&t=262a7dc689229f9905cba8d0000d8b0e',
          coffeename: '抹茶瑞纳冰',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        }, {
          coffeeimg: 'https://img1.baidu.com/it/u=2792718596,1723163661&fm=26&fmt=auto',
          coffeename: '小鹿料多多',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        }, {
          coffeeimg: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fqcloud.dpfile.com%2Fpc%2FLIpUEFVtAGyPgWr-yqgeJQb7fTtvawZ5sAInNXNpiScGuEGVW4L3mx2SmXf5pwCL5g_3Oo7Z9EXqcoVvW9arsw.jpg&refer=http%3A%2F%2Fqcloud.dpfile.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639123277&t=f9835f88b99afd9014352799cf8c6dc3',
          coffeename: '冲绳黑糖拿铁',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        }, {
          coffeeimg: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F16%2F10%2F04%2F2157f3b2880c792.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639123376&t=0c7120755f992fa26ddf398d3bd92ae1',
          coffeename: '摩卡',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        }, {
          coffeeimg: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fqcloud.dpfile.com%2Fpc%2F4zrG0tCu-if32NP4qPJ843CmN584sw6-jCZTOA6ZLg4HEjJJXBYQjVbJZhnXA8kE5g_3Oo7Z9EXqcoVvW9arsw.jpg&refer=http%3A%2F%2Fqcloud.dpfile.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639123407&t=d2530897a42d20199479f5ceeb6089ae',
          coffeename: '焦糖玛奇朵',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        }, {
          coffeeimg: 'https://img1.baidu.com/it/u=3530766208,3669403873&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
          coffeename: '小陨石厚乳',
          coffeeprice: '¥ 28',
          coffeenowprice: '¥9.9'
        }
      ]
    },
  })

效果图:

二、自定义组件

1、介绍

开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。具体参考自定义组件官方文档

2、实现自定义组件

步骤(1)新建存放组件的目录

在项目中新建一个 components 文件夹,用于存放我们以后开发中的组件。

步骤(2)新建组件文件夹

以实现一个自定义tab菜单为例子,我们需要在components目录下新建一个tabMenu文件夹来存放tab菜单组件。然后 右击tabMenu下新建 Component 并命名为tabMenu。

tabMenu文件夹会生成对应的js、json、wxml、wxss4个文件,也就是一个自定义组件的组成部分。

步骤(3)在tabMenu.wxml文件中编写组件模版

<view class="tabMenu">
  <view class="label">{{label}}</view>
  <view class="item {{activeIndex===index?'active':''}}" bindtap="click" data-index="{{index}}"
  wx:for="{{list}}" wx:key="index">{{item}}</view>
</view>

步骤(4)在tabMenu.wxss文件中编写组件样式

.tabMenu {
    display: flex;
    align-items: center;
    margin: 10rpx 0;
}
.tabMenu .label{
    font-weight: bold;
}
.tabMenu .item{
    border: 2rpx solid #ccc;
    padding: 5rpx 10rpx;
    margin: 0 5rpx;
    color: #8fb2c9;
}
.tabMenu .item.active{
    background-color: #8fb2c9;
    color: white;
}

步骤(5)编写tabMenu.js文件

js文件中,使用Component 构造器定义组件,并提供组件的属性、数据、方法等。组件的属性值和内部数据将被用于组件 wxml 的渲染。

properties:组件的属性列表,用于定义组件需要传递的属性。属性设置中可包含三个字段,type表示属性类型、value表示属性初始值、observer表示属性值被更改时的响应函数。
data:组件的内部数据,和properties一同用于组件的模板渲染。
methods:组件的方法列表,包括事件响应函数和任意的自定义方法。(在页面js文件中定义方法不需要写在methods中,注意区分。)
triggerEvent方法: 触发一个自定义事件,将值通过事件对象的方式回传出去。(因为组件内部的值发生变化时,页面内部的数据并不会随之改变。所以就需要通过触发自定义事件,将值回传出去)

Component({
  /**
   * 组件的属性列表,定义组件需要传递的属性
   */
  properties: {
    // 菜单标题
    label:{              // 属性名  
      type:String,       // 类型(必填),类型包括String、Number、Boolean、Object、Array、null(表示任意类型)
      value:''           // 默认值,设置为空
    },
    // 菜单选项内容
    list:{
      type:Array         // 类型是数组
    },
    // 高亮索引
    activeIndex:{
      type:Number,     // 类型是Number   
      value:0          // 默认值是0
    }
  },
  /**
   * 组件的初始数据
   */
  data: {    
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 选项点击事件
    click(e) {
      let {index} = wx.$key(e)      // 获取数据参数index
      this.setData({
        activeIndex: index        // 更新高亮索引
      })
      // 触发一个自定义事件,将值通过事件对象的方式回传出去
      this.triggerEvent('syncData',index)
    }
  }
})

步骤(6)页面中引入tabMenu组件

引入组件有两种方式:① 全局引入,在app.json文件中引入组件;② 局部引入,只在需要使用该组件的页面json文件中引入。
我选择了局部引入,在需要使用组件的shopcart页面中引用。
引用格式:"组件名":"组件路径"

shopcart.json文件:

{
  "usingComponents": {
    "tabMenu":"/components/tabMenu/tabMenu"
  }
}

shopcart.wxml文件:
注意:在组件中通过triggerEvent定义的触发事件,在页面中调用格式为bind:事件名=""。例如bind:syncData="syncData"。

<view class="shopcart">
    {{sugarActive}}--{{plActive}}--{{wdActive}}
    <!-- 使用组件时,传递list属性、label属性和activeIndex属性 -->
    <tabMenu data-active="sugarActive" label="甜度:" list="{{sugars}}" activeIndex="{{sugarActive}}" bind:syncData="syncData"></tabMenu>
    <tabMenu data-active="plActive" label="配料:" list="{{pls}}" activeIndex="{{plActive}}" bind:syncData="syncData"></tabMenu>
    <tabMenu data-active="wdActive" label="温度:" list="{{wds}}" activeIndex="{{wdActive}}" bind:syncData="syncData"></tabMenu>
</view>

shopcart.js文件:

Page({
  data: {
    // 定义一个甜度数组
    sugars: ['全糖', '半糖', '少糖', '无糖'],
    // 甜度高亮索引
    sugarActive: 0,
    // 定义一个配料数组
    pls: ['珍珠', '红豆', '椰果', '布丁'],
    // 配料高亮索引
    plActive: 0,
    // 定义一个温度数组
    wds: ['常温', '多冰', '少冰', '去冰'],
    // 温度高度索引
    wdActive: 0,
  },
 
  //同步组件回传的数据
  syncData(e){
    //获取data参数(获取指定的active)
    let {active} = e.currentTarget.dataset
    //获取组件内部回传的值
    let {detail} = e
    this.setData({
      //给指定的active重新赋值
      [active]:  detail
    })
  }
})

步骤(7)自定义tab菜单效果

3、slot插槽的使用

使用组件时,如果要显示两个组件标签中间的内容,需要使用slot插槽。

(1)tabMenu.wxml文件

组件中的slot标签,用于定义插槽。使用组件时,两个组件标签中间的内容都会放到插槽中。

<view class="tabMenu">
    <view class="label">{{label}}</view>
    <view class="item {{activeIndex===index?'active':''}}" wx:for="{{list}}" wx:key="index" bindtap="click" data-index="{{index}}" >{{item}}</view>
    <slot></slot>
</view>

(2)shopcart.wxml文件

调用组件的页面,在自定义组件标签中添加slot属性,就可以使用插槽。

<tabMenu slot data-active="wdActive" label="温度:" list="{{wds}}" activeIndex="{{wdActive}}" bind:syncData="syncData">
    插槽内容
</tabMenu>

(3)页面效果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容