零、文章目录

微信小程序07-开发进阶

1、案例:自定义标签栏

(1)案例分析
  • 需求:通过前面的学习,我们知道微信小程序的底部标签栏可以在app.json全局配置文件中通过添加tabBar配置项的属性来实现。但是在实际开发中,底部标签栏会有不同的需求,例如需要设计更美观的样式或者需要添加更多的功能,此时就需要自定义标签栏。
(2)知识储备-创建自定义组件
  • 自定义组件

    • 在实际开发中,可能会遇到多个页面中有相同功能区域的情况。例如,多个页面中都有搜索栏。如果为每个页面复制同一份代码,会造成代码冗余,而且不利于后期代码维护。此时,开发者可以将页面内的重复部分封装成自定义组件,以便于在不同的页面中重复使用,从而有助于代码维护。
    • 一个自定义组件是由JSON、JS、WXML和WXSS这4个文件组成的,自定义组件的组成文件通常存放在项目的components目录中,并且为了保证目录结构的清晰,通常会将不同的组件放在不同的子目录下。
  • 创建自定义组件

    • ①打开微信开发者工具,创建一个新项目或打开现有项目。

    • ②在项目的根目录中右键单击,选择“新建文件夹”,然后输入新文件夹的名称“components”,按回车键确认。

    • ③在components文件夹上右键单击,选择“新建文件夹”,然后输入新文件夹的名称“test”,按回车键确认。

    • ④在test文件夹上右键单击,选择“新建Component”,然后输入组件的名称“test”,按回车键确认。确认后,微信开发者工具会自动生成组件的JS、JSON、WXML和WXSS文件。

    • 组件和页面的JS与JSON文件区别如下

      • ①组件的JSON文件中需要声明component属性,将属性值设为true,表示它是一个组件,而页面的JSON文件不需要添加该属性。

      • ②组件的JS文件中调用的是Component()函数,而页面的JS文件调用的是Page()函数。

      • ③组件的事件处理函数需要定义到methods中,页面的事件处理函数需要定义在Page({})中。

微信小程序07-开发进阶-LMLPHP

(2)知识储备-使用自定义组件
  • 自定义组件创建完成后,在使用自定义组件之前,首先要引用自定义组件,需要提供每个自定义组件的标签名和对应自定义组件的文件路径。

  • 自定义组件的引用方式分为局部引用全局引用

    • 在页面的JSON文件中引用自定义组件的方式称为局部引用,局部引用的自定义组件只能在当前被引用的页面内使用;
    • 在app.json全局配置文件中引用组件的方式称为全局引用,全局引用的自定义组件可以在每个页面中使用。
  • 局部引用

    • 在pages/index/index.json文件中添加引用自定义组件的代码
    "usingComponents": {
      "test": "/components/test/test"
    }
    
    • 在pages/index/index.wxml文件中通过<test>标签使用自定义组件
    <test></test>
    
  • 全局引用

    • 全局配置文件app.json文件中添加引用自定义组件的代码
    "usingComponents": {
      "test": "/components/test/test"
    }
    
    • 在pages/index/index.wxml文件中,通过<test>标签使用组件
    <test></test>
    
(2)知识储备-用自定义组件渲染标签栏
  • 微信小程序允许开发者使用自定义组件渲染标签栏,这样开发者就能自定义标签栏的显示效果,并且可以为自定义标签栏添加功能。

  • 首先在app.json文件中配置两个页面

"pages": [
  "pages/home/home",
  "pages/message/message"
],
  • 然后在app.json文件的tabBar配置项中添加"custom": true开启自定义标签栏
"tabBar": {
  "custom": true,
  "list": [{
    "pagePath": "pages/home/home"
  }, {
    "pagePath": "pages/message/message"
  }]
} 
  • 在项目根目录下创建名称为custom-tab-bar的文件夹,并在该文件夹中创建名称为index的组件,最后使用自定义组件的方式编写index组件即可。
(2)知识储备-Vant Weapp组件库
  • Vant Weapp组件库

    • 在微信小程序实际开发中,内置的组件经常无法满足需求,手动编写自定义组件又会花费大量的时间,此时可以使用市场上成熟的开源组件库,提高开发效率。
    • Vant Weapp是有赞前端团队开发的一套开源的微信小程序UI组件库,其界面风格统一、功能齐全,受到广泛关注。Vant Weapp组件库提供了一整套UI基础组件和业务组件,能够快速搭建出风格统一的页面。
    • 若要在微信小程序中使用Vant Weapp组件库,需要利用Node.js提供的npm命令将Vant Weapp组件库安装到项目中,并在项目中进行一些配置。
  • 具体的使用步骤如下

    • ①在微信开发者工具中创建一个新的微信小程序项目,项目名称为“Vant”。
    • ②打开命令提示符,切换工作目录到本项目的根目录,然后在命令提示符中执行以下命令,生成package.json文件。
    npm init -y
    
    • ③在命令提示符中执行以下命令,安装Vant Weapp包。
    npm install @vant/weapp@1.10.4 -S –production
    
    • ④修改app.json全局配置文件,将里面的"style": "v2"配置项删除,该配置项表示使用微信小程序的新版基础组件样式,删除该配置项表示使用旧版基础组件样式。Vant Weapp组件库需要覆盖基础组件样式才能生效,由于新版基础组件样式难以覆盖,可能会出现样式混乱的问题,所以应使用旧版基础组件样式。
    • ⑤构建npm。微信小程序不能直接使用npm安装的包,需要将npm安装的包转换成微信小程序可以使用的包,具体方法是在微信开发者工具的菜单栏中执行“工具”→“构建npm”命令。
      • miniprogram_npm是构建npm完成后的包的存放目录
      • node_modules是npm安装的包的存放目录。

    微信小程序07-开发进阶-LMLPHP

  • 代码演示button组件使用

    • 在app.json文件或页面的JSON文件的usingComponents配置项中引入button组件,以app.json文件为例。
    "usingComponents": {
      "van-button": "@vant/weapp/button/index"
    }
    
    • 在pages/index/index.wxml文件中使用button组件。
    <van-button type="primary">按钮</van-button>
    
(3)案例实现
  • 准备工作

    • ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“自定义标签栏”,模板选择“不使用模板”。
    • ②安装Vant Weapp组件库。根据知识储备中的步骤进行安装。
    • ③创建images文件夹。复制需要的图片素材进去,该文件夹保存了自定义标签栏的图片。
  • 项目初始化

    • ①创建自定义组件。在项目根目录下创建custom-tab-bar文件夹,然后在custom-tab-bar文件夹中创建index组件。
    • ②编写全局配置文件app.json。
    {
      "pages": [
        "pages/home/home",
        "pages/message/message",
        "pages/contact/contact"
      ],
      "window": {
        "backgroundTextStyle": "light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "自定义标签栏",
        "navigationBarTextStyle": "black"
      },
      "tabBar": {
        "custom": true,
        "list": [{
          "pagePath": "pages/home/home"
        }, {
          "pagePath": "pages/message/message"
        }, {
          "pagePath": "pages/contact/contact"
        }]
      },
      "usingComponents": {
        "van-tabbar": "@vant/weapp/tabbar/index",
        "van-tabbar-item": "@vant/weapp/tabbar-item/index"
      },
      "sitemapLocation": "sitemap.json"
    }
    
    • ③编写3个页面中的内容。以pages/home/home页面为例,编写pages/home/home.wxml文件。
    <!--pages/home/home.wxml-->
    <view>首页</view>
    
  • **实现标签栏页面布局:**在custom-tab-bar/index.wxml文件中实现页面布局

<!--components/custom-tab-bar/index.wxml-->
<van-tabbar active="{{ active }}" bind:change="onChange">
  <van-tabbar-item wx:for="{{ list }}" wx:key="index" name="{{ item.name }}">
    <image slot="icon" src="{{ item.iconPath }}" mode="aspectFit" style="width: 30px; height: 18px;" />
    <image slot="icon-active" src="{{ item.selectedIconPath }}" mode="aspectFit" style="width: 30px; height: 18px;" />
    {{ item.text }}
  </van-tabbar-item>
</van-tabbar>
  • 实现标签栏页面逻辑

    • 在custom-tab-bar/index.js文件中编写标签栏逻辑。
    // components/custom-tab-bar/index.js
    Component({
      /**
       * 组件的属性列表
       */
      properties: {
    
      },
    
      /**
       * 组件的初始数据
       */
      data: {
        active: 'home',
        list: [{
          // "pagePath": "/pages/home/home",
          "text": "首页",
          "iconPath": "/images/tabs/home.png",
          "selectedIconPath": "/images/tabs/home-active.png",
          "name": "home"
        }, {
          // "pagePath": "/pages/message/message",
          "text": "消息",
          "iconPath": "/images/tabs/message.png",
          "selectedIconPath": "/images/tabs/message-active.png",
          "name": "message"
        }, {
          "pagePath": "/pages/contact/contact",
          "text": "联系我们",
          "iconPath": "/images/tabs/contact.png",
          "selectedIconPath": "/images/tabs/contact-active.png",
          "name": "contact"
        }]
      },
    
    
      /**
       * 组件的方法列表
       */
      methods: {
        onChange({ detail }) {
          wx.switchTab({
            url: `/pages/${ detail }/${ detail }`,
          })
        }
      }  
    })
    
    • 在pages/home/home.js文件的Page({})中编写onShow()函数,将该页面对应的标签项激活。
    onShow: function () {
      this.getTabBar().setData({
        active: 'home'
      })
    }, 
    
    • 在pages/message/message.js文件的Page({})中编写onShow()函数,将该页面对应的标签项激活。
    onShow: function () {
      this.getTabBar().setData({
        active: 'message'
      })
    }, 
    
    • 在pages/contact/contact.js文件的Page({})中编写onShow()函数,将该页面对应的标签项激活。
    onShow: function () {
      this.getTabBar().setData({
        active: 'contact'
      })
    }, 
    
  • 页面实现效果

微信小程序07-开发进阶-LMLPHP

2、案例:电影列表

(1)案例分析
  • 需求:电影列表”微信小程序用于展示正在热映的电影。
  • “电影列表”微信小程序利用WeUI组件库实现页面效果,页面顶部有一个标签栏,标签栏中有3个标签项,分别是“正在热映”“搜索”“分类”,当用户点击其中一个标签项时,就会跳转到对应的标签页。
  • 页面顶部的标签栏使用了WeUI组件库中的tab和navbar组件。
    • “正在热映”标签页使用了WeUI组件库中的panel组件;
    • “搜索”标签页使用了WeUI组件库中的searchbar组件;
    • “分类”标签页使用了WeUI组件库中的grid组件。
(2)知识储备-WeUI组件库
  • 在微信小程序开发中,经常会遇到多人协作开发的情况,不同开发者的风格不同,很难做到风格统一。微信官方设计团队为微信移动Web开发量身设计了一套与微信原生视觉体验一致的组件库——WeUI,该组件库可以让用户的使用感知更加统一。

  • 在微信小程序中引入WeUI组件库有两种方式

    • 通过useExtendedLib扩展库引入WeUI组件库:app.json文件中的useExtendedLib配置项用于添加扩展库,通过这种方式引入的组件将不会计入代码包大小。在app.json文件中添加配置。

      "useExtendedLib": {
        "weui": true
      },
      
    • 通过npm构建的方式引入WeUI组件库

      • ①打开命令提示符,切换工作目录到当前项目的根目录,然后在命令提示符中执行如下命令,生成package.json文件。
      npm init -y
      
      • ②安装WeUI组件库。在项目根目录下执行以下命令进行安装。
      npm install weui-miniprogram@1.2.3 --save
      
      • ③构建npm。打开微信小程序开发工具,在菜单栏中执行“工具”→“构建npm”命令,构建完成后会在项目根目录生成miniprogram_npm文件夹。
      • ④在项目的app.wxss文件中引入WeUI组件库
      @import 'miniprogram_npm/weui-miniprogram/weui-wxss/dist/style/weui.wxss';
      
  • WeUI组件库中的组件有两种类型

    • 一种是直接通过class样式类使用的组件
    • 另一种是需要在页面的JSON文件或app.json文件中引入的组件。
    • 关于这些组件的详细用法可以参考WeUI官方文档。
  • 代码演示使用dialog弹窗组件

    • 在pages/index/index.json文件中引入dialog弹窗组件。
    {
      "usingComponents": {
        "mp-dialog": "/miniprogram_npm/weui-miniprogram/dialog/dialog"
      }
    }
    
    • 在pages/index/index.wxml文件中使用dialog弹窗组件。
    <!--index.wxml-->
    <mp-dialog title="微信小程序" show="{{ show }}" bindbuttontap="tapDialogButton" buttons="{{ buttons }}">
      <view>好好学习,天天向上!!!</view>
    </mp-dialog>
    
    • 在pages/index/index.js文件中编写页面逻辑。
    // index.js
    Page({
      data: {
        show: true,
        buttons: [{
            text: '取消'
          },
          {
            text: '确认'
          }
        ]
      },
      tapDialogButton: function (e) {
        console.log(e.detail)
        this.setData({
          show: false
        })
      }
    })
    
(2)知识储备-navigator组件
  • navigator组件

    • 在HTML中,<a>标签可以实现页面间的跳转。
    • 在WXML中,navigator组件常用于实现页面之间的跳转。
    <navigator>navigator组件</navigator>
    
    • navigator组件的常用属性如下。

    微信小程序07-开发进阶-LMLPHP

    • navigator组件的open-type属性用于指定跳转方式,常用的open-type合法值如下。
      • 跳转tabBar页面,必须设置open-type属性值为switchTab;
      • 跳转非tabBar页面且保留当前页面,设置open-type属性值为navigate时open-type属性可以省略。

    微信小程序07-开发进阶-LMLPHP

  • 代码演示

    • 创建pages/index/index和pages/detail/detail这两个页面。
    • 在pages/index/index.wxml文件中添加navigator组件,实现点击“跳转到详情页”的时候进行页面跳转。
    <navigator url="/pages/detail/detail?id=1" open-type="navigate">跳转到详情页</navigator>
    
    • 在pages/detail/detail.js文件的onLoad()函数中输出options参数的值。
    onLoad: function(options) {
      console.log(options)
    }
    
(3)案例实现
  • 准备工作

    • ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“电影列表”,模板选择“不使用模板”。
    • ②配置页面。本项目中的页面文件如下。

    微信小程序07-开发进阶-LMLPHP

    • ③配置导航栏。在pages/index/index.json文件中配置页面导航栏。
    • ④配置样式和图片。在pages/index/index.wxss文件中配置样式,在images文件夹中放入图片素材。
    • ⑤通过useExtendedLib扩展库的方式引入WeUI组件库,在全局配置文件app.json中添加配置
    "useExtendedLib": {
      "weui": true
    } 
    

    微信小程序07-开发进阶-LMLPHP

  • **实现标签栏页面结构:**在pages/index/index.wxml文件中编写页面结构。

<!--index.wxml-->
<view class="page" data-weui-theme="{{ theme }}" data-weui-mode="{{ mode }}">
  <view class="page__bd" style="height: 100%;">
    <view class="weui-tab">
      <!-- 标签栏 -->
      <view class="weui-navbar">
        <block wx:for="{{ tabs }}" wx:key="index">
          <view aria-selected="{{ activeIndex == index ? true: false }}" id="{{ index }}" class="weui-navbar__item {{ activeIndex == index ? 'weui-bar__item_on' : '' }}" aria-role="tab" bindtap="tabClick">
            {{ item }}
          </view>
        </block>
      </view>
      <!-- 正在热映 -->
      <view id="panel1" aria-labelledby="tab1" class="weui-tab__panel" aria-role="tabpanel" hidden="{{ activeIndex != 0 }}">
        <include src="tab1.wxml" />
      </view>
      <!-- 搜索 -->
      <view id="panel2" aria-labelledby="tab2" class="weui-tab__panel" aria-role="tabpanel" hidden="{{ activeIndex != 1 }}">
        <include src="tab2.wxml" />
      </view>
      <!-- 分类 -->
      <view id="panel3" aria-labelledby="tab3" class="weui-tab__panel" aria-role="tabpanel" hidden="{{ activeIndex != 2 }}">
        <include src="tab3.wxml" />
      </view>
    </view>
  </view>
</view>
  • **实现“正在热映”标签页页面结构:**在pages/index/tab1.wxml文件中编写页面结构。
<view class="page__hd">
  <view class="page__title">电影列表</view>
</view>
<view class="page__bd">
  <view class="weui-panel weui-panel_access">
    <view class="weui-panel__bd">
      <navigator wx:for="{{ contents }}" wx:key="index" aria-labelledby="js_p1m1_bd" class="weui-media-box weui-media-box_appmsg" url="../test/test">
        <view aria-hidden="true" class="weui-media-box__hd">
          <image class="weui-media-box__thumb" src="{{ item.poster }}" />
        </view>
        <view aria-hidden="true" id="js_p1m1_bd" class="weui-media-box__bd">
          <text class="weui-media-box__title">{{ item.title }}</text>
          <view class="weui-media-box__desc">{{ item.article }}</view>
        </view>
      </navigator>
    </view>
    <view class="weui-panel__ft">
      <navigator class="weui-cell weui-cell_active weui-cell_access weui-cell_link" url="../index/index">
        <text class="weui-cell__bd">查看更多</text>
        <text class="weui-cell__ft"></text>
      </navigator>
    </view>
  </view>
</view>
  • **实现“搜索”标签页页面结构:**在pages/index/tab2.wxml文件中编写搜索框的页面结构。
<view class="page__bd">
  <view class="weui-search-bar {{ inputShowed ? 'weui-search-bar_focusing' : '' }}" id="searchBar">
    <form class="weui-search-bar__form" aria-role="combobox" aria-haspopup="true" aria-expanded="{{ inputVal.length > 0 ? 'true' : 'false' }}" aria-owns="searchResult">
      <view class="weui-search-bar__box">
        <i class="weui-icon-search"></i>
        <input aria-controls="searchResult" type="text" class="weui-search-bar__input" placeholder="搜索" value="{{ inputVal }}" focus="{{ inputShowed }}" bindinput="inputTyping" />
        <view aria-role="button" aria-label="清除" class="weui-icon-clear" wx:if="{{ inputVal.length > 0 }}" bindtap="clearInput"></view>
      </view>
      <label class="weui-search-bar__label" bindtap="showInput">
        <i class="weui-icon-search"></i>
        <span class="weui-search-bar__text">搜索</span>
      </label>
    </form>
    <view aria-role="button" class="weui-search-bar__cancel-btn" bindtap="hideInput">取消</view>
  </view>
</view>
<view class="page__bd page__bd_spacing">
  <view class="weui-flex">
    <view class="weui-flex__item">
      <view class="placeholder">英雄儿女</view>
    </view>
  </view>
  <view class="weui-flex">
    <view class="weui-flex__item">
      <view class="placeholder">大国工匠</view>
    </view>
    <view class="weui-flex__item">
      <view class="placeholder">大国重器</view>
    </view>
  </view>
  <view class="weui-flex">
    <view class="weui-flex__item">
      <view class="placeholder">长津湖</view>
    </view>
    <view class="weui-flex__item">
      <view class="placeholder">集结号</view>
    </view>
    <view class="weui-flex__item">
      <view class="placeholder">红海行动</view>
    </view>
  </view>
</view>
  • **实现“分类”标签页页面结构:**在pages/index/tab3.wxml文件中编写页面结构。
<view class="weui-grids">
  <navigator class="weui-grid" aria-role="button" url="../index/index" wx:for="{{ grids }}" wx:key="index">
    <view class="weui-grid__icon">
      <image src="../../images/icon_tabbar.png" />
    </view>
    <view class="weui-grid__label">{{ item }}</view>
  </navigator>
</view>
  • **实现页面逻辑:**在pages/index/index.js文件中实现页面逻辑。
// index.js
Page({
  data: {
    activeIndex: 0,
    tabs: [
      '正在热映', '搜索', '分类'
    ],
    contents: [{
      title: '英雄儿女',
      article: '该影片讲述了多位英雄人物的故事,其中有浴血奋战的志愿军英模。',
      poster: '/images/1.jpg',
    }, {
      title: '大国工匠',
      article: '这部影片讲述了不同岗位劳动者用自己的灵巧双手,匠心筑梦的故事。',
      poster: '/images/2.jpg',
    }, {
      title: '我和我的祖国',
      article: '该影片取材新中国成立以来经历的无数个历史性经典瞬间,讲述普通人与国家之间息息相关密不可分的动人故事。',
      poster: '/images/3.jpg',
    }],
    inputShowed: false,
    inputVal: '',
    grids: [
      '爱情', '剧情', '喜剧', '家庭', '动画', '文艺', '都市', '动作', '科幻'
    ]
  },
  tabClick: function (e) {
    this.setData({
      activeIndex: e.currentTarget.id
    })
  },
  inputTyping: function(e) {
    this.setData({
      inputVal: e.detail.value
    })
  },
  showInput: function () {
    this.setData({
      inputShowed: true
    })
  },
  hideInput: function () {
    this.setData({
      inputVal: '',
      inputShowed: false
    })
  },
  clearInput() {
    this.setData({
      inputVal: ''
    })
  },
  

})
  • 页面实现效果

微信小程序07-开发进阶-LMLPHP

09-20 18:01