微信小程序

文章目录

1.微信小程序介绍


微信小程序,简称小程序,英⽂名 Mini Program ,是⼀种不需要下载安装即可使⽤的应⽤,它实现了应⽤“触⼿可及”的梦想,用户扫⼀扫或搜⼀下即可打开试用。

1.1.为什么是微信小程序

  1. 微信有海量用户,而且粘性很高,在微信里开发产品更容易触达⽤⼾;
  2. 推广app的成本太⾼。
  3. 微信小程序开发适配成本低。
  4. 规模小容易试错,然后快速迭代。
  5. 跨平台。

1.2.微信小程序历史

  • 2016年1⽉11⽇,微信之父张小龙时隔多年的公开亮相,解读了微信的四⼤价值观。张小龙指出,越来越多产品通过公众号来做,因为这⾥开发、获取用户和传播成本更低。拆分出来的服务号并没有提供更好的服务,所以微信内部正在研究新的形态,叫**「微信小程序」 需要注意的是,之前是叫做「应用号」 **。
  • 2016年9⽉21⽇,微信⼩程序正式开启内测。在微信生态下,触⼿可及、用完即⾛的微信小程序引
    起⼴泛关注。腾讯云正式上线微信小程序解决方案,提供小程序在云端服务器的技术⽅案。
  • 2017年1⽉9⽇,微信推出的“小程序”正式上线。“小程序”是⼀种⽆需安装,即可使⽤的⼿机“应用”。不需要像往常⼀样下载App,用户在微信中“用完即⾛”。

1.3.疯狂的微信小程序

  1. 微信月活已经达到10.82亿。其中55岁以上的用户也达到6300万
  2. 信息传达数达到450亿,较去年增长18%;视频通话4.1亿次,增长100%
  3. 小程序覆盖超过200+行业,交易额增长超过6倍,服务1000亿+人次,创造出了5000亿+的商业价值。

1.4.还有其他的小程序 不容忽视

  1. 支付宝小程序
  2. 百度小程序
  3. QQ小程序
  4. 今日头条+抖音小程序

1.5.体验

1.5.1.官方微信小程序体验

小程序示例源码

1.5.2. 优秀的微信第三方小程序

  • 拼多多
  • 滴滴出行
  • 欢乐斗地主
  • 智行火车票
  • 唯品会

2.环境准备

开发微信小程序之前,必须要准备好相应的环境

2.1.注册账号

微信小程序需要标注唯一的开发者信息,因此需要申请注册账号。建议使用全新的邮箱(作为登录帐号,请填写未被微信公众平台注册,未被微信开放平台注册,未被个人微信号绑定的邮箱),没有注册过其他小程序或者公众号的。

访问注册页面,耐心完成注册即可。

  • 账户信息

  • 邮箱激活

  • 信息登记

2.2.获取APPID

由于后期调⽤微信⼩程序的接⼝等功能,需要索取开发者的⼩程序中的 APPID ,所以在注册成功后, 可登录,然后获取APPID。

登录成功后可看到如下界面

然后复制你的APPID,悄悄的保存起来,不要给别⼈看到。

2.3.开发工具

下载地址

微信小程序自带开发者工具,集 **开发、预览、调试、发布 **于⼀⾝的 完整环境。

但是由于编码的体验不算好,因此 建议使⽤ vs code + 微信小程序编辑工具 来实现编码

vs code 负责敲代码, 微信编辑工具 负责预览

3.第一个微信小程序

3.1.打开微信开发者工具

注意 第⼀次登录的时候 需要扫码登录

3.2.新建小程序项目

3.3.填写项目信息

3.4.创建成功

4.微信开发者工具介绍

详细的使⽤,可以查看官网

5.小程序结构目录

小程序框架的目标是通过尽可能简单、⾼效的方式让开发者可以在微信中开发具有原生APP体验的服务。

小程序框架提供了自己的视图层描述语言WXML 和 WXSS ,以及 JavaScript (小程序有自己的标签、样式、文件以及逻辑文件),并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑**(我们写代码的时候尽可能少关注操作页面结构,只需要关注页面本身)**。

5.1.小程序文件结构和传统web对比

传统web微信小程序
结构HTMLWXML
样式CSSWXSS
逻辑JavaScriptjavascript
配置JSON

通过以上对比得出,传统web是三层结构。而微信小程序是四层结构,多了⼀层配置.json

5.2.基本的项目目录

6.小程序配置文件

⼀个小程序应用程序会包括最基本的两种配置⽂件。⼀种是全局的app.json和页面自己的page.json

注意:JSON配置文件中不能出现注释

6.1.全局配置app.json

app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界⾯表现、网络超时时间、底部tab等。普通快速启动项目里面的 app.json 配置。如果想将哪个页面作为首页,只需要在pages中放在第一即可。

此时为index页面在第一位置

{
    "pages": [
        "pages/index/index", 
        "pages/logs/logs"
    ], 
    "window": {
        "backgroundTextStyle": "light", 
        "navigationBarBackgroundColor": "#fff", 
        "navigationBarTitleText": "WeChat", 
        "navigationBarTextStyle": "black"
    }, 
    "style": "v2", 
    "sitemapLocation": "sitemap.json"
}

字段的含义

  1. pages 字段⸺用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。

    • pages保存页面路径,不需要保存文件名后缀

    • 新增页面的只需要在微信小程序的开发者工具中编辑app.json的新增页面名称,保存就可以自动生成页面的文件夹以及配置文件。

  2. window 标题⸺定义小程序所有页面的顶部背景颜色,文字颜色定义等。

    具体内容可参考

    其他参考位置

6.1.1.tabbar

下方的页面的导航栏设置在app.jsp配置,主要用于导航操作。

  1. 首先准备导航栏图标样式,同一个功能图标设置两种。一是未点击状态下显示的图标,而是点击状态下显示的图标

  2. 在app.json中进行配置

    {
      "pages":[
        "pages/index/index",
        "pages/img/img",
        "pages/mine/mine",
        "pages/search/search",
        "pages/demo2/demo2",
        "pages/logs/logs",
        "pages/demo1/demo1"
      ],
      "window":{
        "backgroundTextStyle":"dark",
        "navigationBarBackgroundColor": "#0094ff",
        "navigationBarTitleText": "我的应用",
        "navigationBarTextStyle":"white",
        "enablePullDownRefresh": true,
        "backgroundColor":"#FFFF00"
      },
      "tabBar": {
        "list": [{
          "pagePath": "pages/index/index",
          "text": "首页",
          "iconPath": "icon/_home.png",
          "selectedIconPath": "icon/home.png"
        },{
          "pagePath": "pages/img/img",
          "text": "图片",
          "iconPath": "icon/_img.png",
          "selectedIconPath": "icon/img.png"
        },{
          "pagePath": "pages/search/search",
          "text": "搜索",
          "iconPath": "icon/_search.png",
          "selectedIconPath": "icon/search.png"
        },{
          "pagePath": "pages/mine/mine",
          "text": "我的",
          "iconPath": "icon/_my.png",
          "selectedIconPath": "icon/my.png"
        }],
        "color": "#0094ff",
        "selectedColor": "#ff9400",
        "backgroundColor": "#ff5533",
        "position":"buttom"
      },
      "style": "v2",
      "sitemapLocation": "sitemap.json"
    }
    
    • 首先在pages设置所有的显示页面,首页放在第一位置
    • 在tabBar中的list中存放所有导航栏每个按钮的信息。
      • pagePath为跳转的页面地址
      • text为显示提示文本信息
      • iconPath为默认状态下的图标
      • selectedIconPath选中状态下的图标
    • 在tabBar的color设置text为显示提示文本的颜色。
    • 在tabBar的selectedColor设置text为显示提示文本选中后的颜色
    • 在tabBar的position设置tabBar的位置,默认为buttom即在屏幕底部,设置为top则显示在顶部
  3. 显示效果

6.2.pageName.json

这里的page.json其实用来表示页面目录下的page.json 这类和小程序页面相关的配置。

开发者可以独立定义每个页面的⼀些属性,如顶部颜色、是否允许下拉刷新等等。

页面的配置只能设置 app.json 中部分 window 配置项的内容,页面中配置项会覆盖 app.json 的 window 中相同的配置项数据。

属性类型默认值描述
navigationBarBackgroundColorHexColor#000000导航栏背景颜色,如 #000000
navigationBarTextStyleStringwhite导航栏标题颜色,仅⽀持 black / white
navigationBarTitleTextString导航栏标题文字内容
backgroundColorHexColor#ffffff窗口的背景色
backgroundTextStyleStringdark下拉 loading 的样式,仅支持 dark / light
enablePullDownRefreshBooleanfalse是否全局开启下拉刷新。 详见Page.onPullDownRefresh
onReachBottomDistanceNumber50页面上拉触底事件触发时距页面底部距离,单位为px。 详见Page.onReachBottom
disableScrollBooleanfalse设置为 true 则页⾯整体不能上下滚动;只在页面配置中有 效,无法在app.json中设置该项

6.3.sitemap配置-了解即可

小程序根目录下的sitemap.json⽂件⽤于配置小程序及其页面是否允许被微信索引。

7.模板语法

WXML(WeiXin Markup Language)是框架设计的⼀套标签语言,结合基础组件、事件系统,可以构建出页面的结构。

小程序因为存在模板语法,所有才能实现页面渲染和动态功能。

7.1.数据绑定

pageName.js中Page()方法传入一个对象{……},对象有格式要求。data:{},名字是关键字,不可修改,存放初始化数据,其他的都是生命周期函数。

数据绑定的主要内容就是获取pageName.js中的data:{}中的数据,展示出来。

VS CODE可以使用微信小程序开发助手插件辅助编程

7.1.1.普通写法

  1. 准备数据

    Page({
          data: {
            	message: 'Hello MINA!'
         }
    })
    
  2. 获取数据

    <view> {{ message }} </view>
    

7.1.2.组件属性

  1. 准备数据

    Page({
          data: {
            	id: 0
         }
    })
    
  2. 获取数据

    <view id="item-{{id}}"> </view>
    

7.1.3.bool类型

不要直接写 checked=false,其计算结果是⼀个字符串

<checkbox checked="{{false}}"> </checkbox>

7.1.4.示例

  1. 准备数据

    Page({
          /**
           * 页面的初始数据
           */
          data: {
                msg: "hello mina",
                num: 10000,
                isGirl: false,
                person: {
                      age: 74,
                      height: 145,
                      weight: 200,
                      name: "牛"
                },
                isChecked:true
          },
    })
    
  2. 测试

    <!-- 
      1 text 相当于以前web中的 span标签 行内元素  不会换行
      2 view 相当于以前web中的 div标签 块级元素  会换行
      3 checkbox 以前的复选框标签 
     -->
    <!-- <text>1</text>
    <text>2</text>
    <view>1</view>
    <view>2</view> -->
    
    <!-- 1 字符串 -->
    <view> {{msg}} </view>
    <!-- 2 数字类型 -->
    <view>{{num}}</view>
    <!-- 3 bool类型  -->
    <view> 是否是女生: {{isGirl}} </view>
    <!-- 4 object类型 -->
    <view>{{person.age}}</view>
    <view>{{person.height}}</view>
    <view>{{person.weight}}</view>
    <view>{{person.name}}</view>
    
    <!-- 5 在标签的属性中使用 -->
    <view data-num="{{num}}"> 自定义属性</view>
    
    <!-- 
      6 使用bool类型充当属性 checked  
        1 字符串和花括号之间一定不要存在空格 否则会导致识别失败 
          以下写法就是错误的示范
             <checkbox checked="       {{isChecked}}"> </checkbox>
     -->
    <view>
      <checkbox checked="{{isChecked}}"> </checkbox>
    </view>
    
  3. 效果

7.1.5.复杂data数据设置

Page({
    data: {
        userInfo:{},
    },
    
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        //页面加载是接受数据,设置参数
        this.setData({
            userInfo: {
                xm: options.xm,
                sfzh: options.sfzh,
                openid:options.opendid
            },
        })
    },
})

7.2.表达式运算

表达式运算是指可以在花括号中加入表达式进行简单运算

概念区分:

  • 表达式:指的是一些简单运算、数字运算、字符串拼接、逻辑运算。
    1. 数字的加减
    2. 字符串拼接
    3. 三元表达式
  • 语句:指复杂的代码段
    1. if else
    2. switch
    3. do while
    4. for

7.2.1.三元运算

<view hidden="{{flag ? true : false}}"> Hidden </view>

7.2.2.算数运算

Page({
  data: {
    a: 1,
    b: 2,
    c: 3
 }
})
<view> {{a + b}} + {{c}} + d </view>

最终显示结果:3 + 3 + d

7.2.3.逻辑判断

Page({
  data: {
    length:6
 }
})
<view wx:if="{{length > 5}}">大于5</view>

最终结果:大于5

7.2.4.字符串运算

Page({
  data:{
    name: 'Stonebridge'
 }
})
<view>{{"hello," + name}}</view>

最终显示结果:hello,Stonebridge

7.2.5.注意

花括号和引号之间如果有空格,将最终被解析成为字符串

7.2.6.示例

<view>{{1+1}}</view>
<view>{{'1'+'1'}}</view>
<view>{{ 11%2===0 ? '偶数' : '奇数' }}</view>

最终效果:

7.3.列表渲染

7.3.1.列表循环

  1. wx:for="{{数组或者对象}}" wx:for-item=“循环项的名称” wx:for-index=“循环项的索引”

  2. wx:key=“唯一的值” 用来提高列表渲染的性能

    • wx:key 绑定一个普通的字符串的时候那么这个字符串名称肯定是循环数组中的对象的唯一属性

    • wx:key ="*this" 就表示你的数组是一个普通的数组 *this 表示是循环项

      [1,2,3,44,5]
      [“1”,“222”,“adfdf”]

  3. 当出现数组的嵌套循环的时候,尤其要注意以下绑定的名称不要重名

    wx:for-item=“item” wx:for-index="index"

  4. 默认情况下我们不写wx:for-item=“item” wx:for-index=“index”。小程序也会把循环项的名称和索引的名称item和index。故只有一层循环的话 (wx:for-item=“item” wx:for-index=“index”)可以省略。

示例

  1. 准备数据

    Page({
        /**
       * 页面的初始数据
       */
        data: {
            list:[
                    {
                        id:0,
                        name:"尤里"
                    },
                    {
                        id:1,
                        name:"普莱斯"
                    },
                    {
                        id:2,
                        name:"麦克塔维什"
                    }
            	]
        	},
    })
    
  2. 显示数据

     <view>
           <view wx:for="{{list}}" wx:for-item="item" wx:for-index="index" wx:key="id">
             索引:{{index}}
             --
             值:{{item.name}}
           </view>
     </view>
    

    **wx:for-item=“item” wx:for-index=“index”**可省略

  3. 最终效果

7.3.2.对象循环

  1. wx:for="{{对象}}" wx:for-item=“对象的值” wx:for-index=“对象的属性”
  2. 循环对象的时候最好把 item和index的名称都修改一下wx:for-item=“value” wx:for-index=“key”

示例

  1. 准备数据

    Page({
      /**
       * 页面的初始数据
       */
        person: {
          age: 74,
          height: 145,
          weight: 200,
          name: "麦克塔维什"
        }
      },
    })
    
  2. 展示数据

    <view>
       <view>对象循环</view>
       <view wx:for="{{person}}" wx:for-item="value"  wx:for-index="key" wx:key="age">属性:{{key}}--值:{{value}}</view>
     </view>
    
  3. 最终效果

7.3.3.列表循环

result.modlist为一个JSON列表,通过for循环进行遍历,通过编号获取其中的值,进行修改后再赋值进去

var result = JSON.stringify(response);
result = JSON.parse(result);
//遍历首页的功能模块,为其跳转的地址根据功能代码(gndm)为其赋值参数
//1.如果是跳转到H5页面,将地址和参数准备好后使用Base64编码后存放在url中,在container.js中获取后直接解码使用
for (var i = 0; i < result.modlist.length; i++) {
    var module = result.modlist[i];
    if (module.gndm == "WAK01") {
        module.url = Base64.encode(module.url + "?openid=" + userInfo.openid + "&yhdm=" + userInfo.yhdm);
    } else if (module.gndm == "WAK02") {
        module.url = Base64.encode(module.url + "?yhid=" + userInfo.yhdm + "&fydm=" + userInfo.dwdm);
    }
}

7.3.4.block

  1. 占位符的标签
  2. 写代码的时候可以看到这标签存在
  3. 页面渲染小程序会把它移除掉

示例

  1. 展示数据

    <view>
        <block wx:for="{{list}}" wx:for-item="item" wx:for-index="index" wx:key="id" class="my_list">
          索引:{{index}}
          --
          值:{{item.name}}
        </block>
    </view>
    
  2. 最终效果

7.4.条件渲染

7.4.1.wx:if

在框架中,使⽤ wx:if="{{condition}}" 来判断是否需要渲染该代码块,condition为true/false;

以及if , else , if else
wx:if
wx:elif
wx:else

示例:

<view>
     <view>条件渲染</view>
     <view wx:if="{{true}}">显示</view>
     <view wx:if="{{false}}">隐藏</view>

     <view wx:if="{{flase}}">1</view>
     <view wx:elif="{{flase}}">2</view>
     <view wx:else> 3 </view>
</view>

示例:

7.4.2.hidden

  1. 在标签上直接加入属性 hidden
  2. hidden="{{true}}"

示例

<view>
     <view>条件渲染</view>
     <view>---------------</view>
     <view hidden >hidden1</view>
     <view hidden="{{false}}" >hidden2</view>

     <view>-----000-------</view>
     <view wx:if="{{false}}">wx:if</view>
     <view hidden>hidden</view>
</view>

**注意:**hidden属性不要和样式display一起使用

7.4.3.二者选择

**当标签频繁的切换显示的时候 优先使用 hidden通过添加样式的方式来切换显示 **

8.小程序事件的绑定

小程序中绑定事件,通过bind关键字来实现。如bindtap、bindinput、bindchange等不同的组件支持不同的事件,具体看组件的说明即可。

8.1.wxml绑定事件

<input bindinput="handleInput" />

8.2.page定义函数

Page({
      // 绑定的事件
      handleInput: function(e) {
            console.log(e);
            console.log("值被改变了");
     }
})

8.3.注意

  1. 绑定事件时不能带参数不能带括号,以下为错误写法

    <input bindinput="handleInput(100)" />
    
  2. 事件传值通过标签自定义属性的方式 和 value

    <input bindinput="handleInput" data-item="100" />
    
  3. 事件触发时获取数据

    handleInput: function(e) {
        // {item:100}
        console.log(e.currentTarget.dataset)
        // 输入框的值
        console.log(e.detail.value);
    }
    

8.4.示例

需求:

  1. page.WXML

    <input type="text" bindinput="handleInput"/>
    <view>
          {{num}}  
    </view>
    <button style="color:red;background:#0044ff" bindtap="handletap" data-operation="{{1}}">+</button>
    <button style="color:blue;background:#ff4400" bindtap="handletap" data-operation="{{-1}}">-</button>
    
  2. page.JS

    // pages/demo4/demo4.js
    Page({
    
          /**
           * 页面的初始数据
           */
          data: {
                num:0
          },
          handleInput(e){
                this.setData({
                  	num:e.detail.value
                })
                console.log(e.detail.value);
          },
          handletap(e) {
                // console.log(e);
                // 1 获取自定义属性 operation
                const operation = e.currentTarget.dataset.operation;
                this.setData({
                  	num: this.data.num + operation
                })
          }
    })
    

注意点:

  • 需要给input标签绑定input事件绑定关键字 bindinput

  • 如何获取输入框的值通过事件<源对象e>来获取e.detail.value

  • 把输入框的值赋值到data当中

    不能直接

    1. this.data.num=e.detail.value

    2. this.num=e.detail.value

    正确的写法

    this.setData({

    ​ num:e.detail.value

    })

  • 需要加入一个点击事件

    1. bindtap

    2. 无法在小程序当中的事件中直接传参

    3. 通过自定义属性的方式来传递参数

    4. 事件源中获取自定义属性

9.样式WXSS

WXSS( WeiXin Style Sheets )是⼀套样式语言,⽤于描述 WXML 的组件样式。

与 CSS 相比,WXSS 扩展的特性有:

  • 响应式长度单位
  • rpx 样式导入

9.1.尺寸单位

rpx (responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx ,不管使用iPhone,iPad其屏幕宽度均是750rpx,故不同的设备单位rpx的长度(像素)不同

如在 iPhone6 上,屏幕宽度为375px ,共有750个物理像素,则 750rpx = 375px = 750物理像素 , 1rpx = 0.5px = 1物理像素

当我们要做一个页面布局的时候,如果要实现页面的某些元素大小跟随屏幕做自适应变化,就要使用rpx。

设备rpx换算px (屏幕宽度/750)px换算rpx (750/屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

建议: 开发微信小程序时设计师可以⽤ iPhone6 作为视觉稿的标准。

使用步骤:

  1. 确定设计稿宽度 pageWidth
  2. 计算⽐例 750rpx = pageWidth px ,因此 1px=750rpx/pageWidth 。
  3. 在less⽂件中,只要把设计稿中的 px => 750/pageWidth rpx 即可。

9.1.1.像素定义元素长度

  1. wxml

    <view>RPX</view>
    
  2. wxss

    view{
            width:200px;
            height:200px;
            font-size:40px;
            background-color:aqua;
    }
    
  3. 效果

    使用像素定义元素长度不管使用什么设备,元素长度不变。

    iPhone6屏幕

    iPad屏幕

9.1.2.使用rpx定义元素长度

  1. wxss

    view{
            width:200rpx;
            height:200rpx;
            font-size:40rpx;
            background-color:aqua;
    }
    
  2. 效果

    使用rpx定义元素长度,元素长度自适应屏幕比例为该长度在750rpx的长度比例

    • iPhone6屏幕

    • ipad屏幕

9.1.3.总结

  1. 小程序中不需要主动来引入样式文件,页面的会自动引入其样式文件PageName.wxss

  2. 需要把页面中某些元素的单位由px改成 rpx

    • 设计稿 750x

      750 px = 750 rpx

      1 px = 1 rpx

    • 把屏幕宽度 改成 375px

      375 px = 750 rpx

      1 px = 2rpx

      1rpx = 0.5px

  3. 存在一个设计稿宽度100像素(px)在未知页面page像素

    • 设计稿 page存在一个元素宽度100px

    • 拿以上的需求 去实现 不同宽度的页面适配

      page px = 750 rpx

      1px = 750 rpx / page

      100 px = 750 rpx * 100 / page

  4. 利用一个属性calc属性 css 和 wxss 都支持一个属性

    width:calc(750rpx * 100 / 375);,375为屏幕像素

    • 750 和 rpx 中间不要留空格
    • 运算符的两边也不要留空格

    示例:

     view{
       /* width: 200rpx; */
       height: 200rpx;
       font-size: 40rpx;
       background-color: aqua;
      /* 以下代码写法是错误  */
      /*  width:750 rpx * 100 / 375 ;  */
      width:calc(750rpx * 100 / 375);
     }
    

    效果

9.2.样式导入

wxss中直接就⽀持,样式导⼊功能。

也可以和 less中的导⼊混⽤。

使用@import 语句可以导⼊外联样式表,只⽀持相对路径。

  1. 创建style/common.wxss

    view{
      color: aqua;
      font-size: 100px;
    }
    
  2. 在页面的wxss中引入

    /* 
    1 引入的 代码 是通过 @import 来引入
    2 路径 只能写相对路径
     */
    @import "../../styles/common.wxss";
    

9.3.选择器

特别需要注意的是小程序不支持通配符 * 因此以下代码无效!

*{
    margin:0;
    padding:0;
    box-sizing:border-box;
}

解决方案:view,text,img{……}

目前支持的选择器有:

选择器样例样例描述
.class.intro选择所有拥有 class=intro 的组件
#id#firstname选择拥有 id=firstname 的组件
elementview选择所有 view 组件
element, elementview, checkbox选择所有⽂档的 view 组件和所有的 checkbox 组 件
nth-child(n)view:nth-child(n)选择某个索引的标签
::afterview::after在 view 组件后边插⼊内容
::beforeview::before在 view 组件前边插⼊内容

9.4.小程序中使用less

原⽣⼩程序不⽀持 less ,其他基于⼩程序的框架⼤体都⽀持,如 wepy , mpvue , taro 等。 但是仅仅因为⼀个less功能,⽽去引⼊⼀个框架,肯定是不可取的。因此可以⽤以下⽅式来实现

  1. 编辑器是 vscode

  2. 安装插件 easy less

  3. 在vs code的设置中settings.json加入如下

     "less.compile": {
            "outExt":".wxss"
       }
    
  4. 在要编写样式的地⽅,新建 less ⽂件,如 index.less ,然后正常编辑即可。

10.常见组件

重点讲解小程序中常⽤的布局组件 view,text,rich–text,button,image,navigator,icon,swiper,radio,checkbox。 等

10.1.view

代替原来的 div 标签

<view hover-class="h-class">
    点击我试试
</view>

10.2.text

  1. ⽂本标签
  2. 只能嵌套text
  3. ⻓按⽂字可以复制(只有该标签有这个功能) ,增加selectable属性即可
  4. 可以对空格 回⻋ 进⾏编码,增加decode属性即可
属性名类型默认值说明
selectableBooleanfalse⽂本是否可选
decodeBooleanfalse是否解码

示例:

  1. 不使用decode属性

    <!-- 
      1 长按文字复制 selectable
      2 对文本内容 进行 解码
     -->
    <text selectable>
      text &nbsp; 123 &lt;
    </text>
    
    

    效果

  2. 使用decode属性

    <text selectable decode>
      text &nbsp; 123 &lt;
    </text>
    

10.3.image

  1. 图片标签,image组件默认宽度320px、⾼度240px
  2. ⽀持懒加载
  3. 建议最好把图片放在网络上,通过src引用
属性名类型默认值说明
srcString图⽚资源地址
modeStringscaleToFill图⽚裁剪、缩放的模式
lazy-loadBooleanfalse图⽚懒加载

mode 有效值:

mode 有 13 种模式,其中 4 种是缩放模式,9.种是裁剪模式。

模式说明
缩放scaleToFill不保持纵横比缩放图片,使图片的宽⾼完全拉伸⾄填满image 元素
缩放aspectFit保持纵横比缩放图片,使图片的长边能完全显⽰出来。
缩放aspectFill保持纵横比缩放图片,只保证图片的短边能完全显⽰出来。
缩放widthFix宽度不变,⾼度⾃动变化,保持原图宽⾼⽐不变
裁剪top不缩放图片,只显示图片的顶部区域
裁剪bottom不缩放图片,只显示图片的底部区域
裁剪center不缩放图片,只显示图片的中间区域
裁剪left不缩放图片,只显示图片的左边区域
裁剪right不缩放图片,只显示图片的右边区域
裁剪top left不缩放图片,只显示图片的左上边区域
裁剪top right不缩放图片,只显示图片的右上边区域
裁剪bottom left不缩放图片,只显示图片的左下边区域
裁剪bottom right不缩放图片,只显示图片的右下边区域

示例:

  1. WXML

    <!-- 
      image 图片标签
      1 src 指定要加载的图片的路径
        图片存在默认的宽度和高度 320 * 240      原图大小是 200 * 100
      2 mode 决定 图片内容 如何 和 图片标签 宽高 做适配
        1 scaleToFill 默认值 不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素 
        2 aspectFit 保持宽高比 确保图片的长边 显示出来   页面轮播图 常用
        3 aspectFill 保持纵横比缩放图片,只保证图片的 短 边能完全显示出来。  少用
        4 widthFix 以前web的图片的 宽度指定了之后 高度 会自己按比例来调整   常用  
        5 bottom。。 类似以前的backgroud-position 
      3 小程序当中的图片 直接就支持 懒加载  lazy-load
        1 lazy-load 会自己判断 当 图片 出现在 视口  上下 三屏的高度 之内的时候  自己开始加载图片 
     -->
     <image mode="widthFix" lazy-load src="https://tva2.sinaimg.cn/large/007DFXDhgy1g51jlzfb4lj305k02s0sp.jpg" />
    
  2. WXSS

    image{
      box-sizing: border-box;
      border: 1px solid red;
    
      width: 300px;
      height: 200px;
    }
    
  3. 效果

    宽度不变,高度自动变化,保持原图宽高比不变

10.4.swiper

微信内置轮播图组件

轮播图的默认宽度 100% 高度 150px

属性名类型默认值说明
indicator-dotsBooleanfalse是否显⽰⾯板指⽰点(小圆点)
indicator-colorColorrgba(0, 0, 0, .3)指⽰点(小圆点)颜⾊
indicator-active-colorColor#000000当前选中的指⽰点(小圆点)颜⾊
autoplayBooleanfalse是否⾃动切换
intervalNumber5000⾃动切换时间间隔
circularBooleanfalse是否循环轮播

10.4.1.swiper

滑块视图容器。

10.4.2.swiper-item

滑块

滑块 默认宽度和⾼度都是100%

10.4.3.示例

  1. WXML

    <!-- 
      1 轮播图外层容器 swiper
      2 每一个轮播项 swiper-item
      3 swiper标签 存在默认样式
        1 width 100% 默认横向占满整个屏幕
        2 height 150px (高度无法实现由内容撑开 )
      4 根据原图的长宽等比例给swiper定宽度和高度
        原图的宽度和高度  1125 * 352 px
        swiper 宽度 / swiper  高度 =  原图的宽度  /  原图的高度
        swiper  高度  =  swiper 宽度 *  原图的高度 / 原图的宽度
        height: 100vw * 352 /  1125
    	具体实现看WXSS
      5 autoplay 自动轮播
      6 interval 修改轮播时间
      7 circular 衔接轮播
      8 indicator-dots 显示指示器、分页器、索引器(轮播中的小圆点)
      9 indicator-color 指示器的未选择的颜色 
      10 indicator-active-color 选中的时候的指示器的颜色 
     -->
    <swiper autoplay interval="1000" circular indicator-dots indicator-color="#0094ff" indicator-active-color="#ff0094">
        <swiper-item> 
            <image mode="widthFix" src="//gw.alicdn.com/imgextra/i1/44/O1CN013zKZP11CCByG5bAeF_!!44-0-lubanu.jpg" /> 			</swiper-item>
        <swiper-item> 
            <image mode="widthFix" src="//aecpm.alicdn.com/simba/img/TB1CWf9KpXXXXbuXpXXSutbFXXX.jpg_q50.jpg" /> 
        </swiper-item>
        <swiper-item> 
            <image mode="widthFix" src="//gw.alicdn.com/imgextra/i2/37/O1CN01syHZxs1C8zCFJj97b_!!37-0-lubanu.jpg" /> 		 	</swiper-item>
    </swiper>
    
  2. WXSS

    /* pages/demo10/demo10.wxss */
    swiper {
      width: 100%;
      /* height: calc(100vw * 352 /  1125); */
      height: 31.28vw;/*calc(100vw * 352 /  1125)的结果*/
    }
    image {
      width: 100%;
    }
    
  3. 效果

10.5.navigator

导航组件 类似超链接标签

属性名类型默认值说明
targetStringself在哪个目标上发⽣跳转,默认当前小程序,可选值 self/miniProgram
urlString当前小程序内的跳转链接
opentypeStringnavigate跳转方式

open-type 有效值:

说明
navigate保留当前页面,跳转到应⽤内的某个页面,但是不能跳到tabbar 页面
redirect关闭当前页面,跳转到应⽤内的某个页面,但是不允许跳转到tabbar 页面。
switchTab跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
reLaunch关闭所有页面,打开到应⽤内的某个页面
navigateBack关闭当前页面,返回上一页⾯或多级页面。可通过 getCurrentPages() 获取当 前的页⾯栈,决定需要返回几层
exit退出小程序,target=miniProgram时⽣效

示例

  1. WXML

    <!--
      导航组件navigator
      1.块级元素,默认会换行,可以直接加宽度和高度
      2.url要跳转的页面路径:绝对路径/相对路径
      3.target要跳转到当前的小程序,还是其他的小程序页面
          self(默认值):自己小程序
          或者其他小程序的页面
      4.open-type:跳转的方式
        1 navigate 默认值 	保留当前页面(可返回),跳转到应用内的某个页面,但是不能跳到 tabbar 页面
        2 redirect	关闭当前页面(不可返回),跳转到应用内的某个页面,但是不允许跳转到 tabbar 页面。
        3 switchTab	跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
        4 reLaunch	关闭所有页面,打开到应用内的某个页面
    -->
     <navigator url="/pages/demo10/demo10"> open-type的默认值(navigate)轮播图页面 </navigator>
     <navigator url="/pages/index/index">open-type的默认值(navigate) 不能直接跳转到 tabbar页面 </navigator>
     <navigator open-type="redirect" url="/pages/demo10/demo10"> open-type的redirect 轮播图页面  </navigator>
     <navigator open-type="switchTab" url="/pages/index/index">  switchTab直接跳转到 tabbar页面 </navigator>
     <navigator open-type="reLaunch" url="/pages/index/index">  reLaunch 可以随便跳 </navigator> 
    
    
  2. 效果

10.6.rich-text

富文本标签

可以将字符串解析成 对应标签,类似 vue中 v–html 功能

10.6.1.nodes属性

nodes 属性⽀持 字符串 和 标签节点数组

属性说明类型必填备注
name标签名string⽀持部分受信任的 HTML 节点
attrs属性object⽀持部分受信任的属性,遵循 Pascal 命名法
children⼦节点列表array结构和 nodes ⼀致

⽂本节点:type = text

属性说明类型必填备注
text⽂本string⽀持entities
  1. nodes 不推荐使⽤ String 类型,性能会有所下降。
  2. rich–text 组件内屏蔽所有节点的事件。
  3. attrs 属性不⽀持 id ,⽀持class 。
  4. name 属性大小写不敏感。 如果使⽤了不受信任的 HTML 节点,该节点及其所有子节点将会被移除。
  5. img 标签仅⽀持⽹络图⽚。

示例1:

  1. js(拷贝淘宝主页div串)

    // pages/demo12/demo12.js
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
            html:'<div class="tpl-wrapper" data-tpl-id="m_h_v31icon_1" style="margin-top: -10px;">……</div></div>'
      },
    })
    
  2. wxml

    <!-- 
      rich-text 富文本标签
      1 nodes属性来实现
        1 接收标签字符串 
        2 接收对象数组 
     -->
     <rich-text nodes="{{html}}"></rich-text>
    
  3. 效果

示例2:

  1. js

    // pages/demo12/demo12.js
    Page({
      data: {
        // 1 标签字符串 最常用的
        // 2 对象数组
        html:[
          {
            // 1 div标签 name属性来指定
            name:"div",
            // 2 标签上有哪些属性
            attrs:{
              // 标签上的属性 class  style
              class:"my_div",
              style:"color:red;"
            },
            // 3 子节点 children 要接收的数据类型和 nodes第二种渲染方式的数据类型一致 
            children:[
              {
                name:"p",
                attrs:{},
                // 放文本
                children:[
                  {
                    type:"text",
                    text:"hello"
                  }
                ]
              }
            ]
          }
        ]
      }
    })
    
  2. WXML

    同示例1

  3. 效果

10.7.button

<!-- 
  button 标签
  1 外观的属性
    1 size 控制按钮的大小
      1 default 默认大小
      2 mini 小尺寸
    2 type 用来控制按钮的颜色
      1 default 灰色
      2 primary 绿色
      3 warn 红色
    3 plain  按钮是否镂空,背景色透明
    4 loading 文字前显示正在等待图标
 -->
<button>默认按钮</button>
<button size="mini">mini 默认按钮</button>
<button type="primary"> primary按钮</button>
<button type="warn"> warn按钮</button>
<button type="warn" plain> plain按钮</button>
<button type="primary" loading>primary按钮</button>
属性类型默认值必填说明
sizestringdefault按钮的大小
typestringdefault按钮的样式类型
plainbooleanfalse按钮是否镂空,背景⾊透明
disabledbooleanfalse是否禁⽤
loadingbooleanfalse名称前是否带 loading 图标
form-typestring⽤于 组件,点击分别会触发 组件的 submit/reset 事件
form-typestring微信开放能⼒

size 的合法值

说明
default默认大小
mini⼩尺⼨

type 的合法值

说明
primary绿⾊
default⽩⾊
warn红⾊

form-type 的合法值

说明
submit提交表单
reset重置表单

open-type 的合法值

说明
contact打开客服会话,如果用户在会话中点击消息卡片后返回⼩程序,可以从 bindcontact 回调中获得具体信息,具体说明
share触发用户转发,使⽤前建议先阅读使用指引
getPhoneNumber获取用户手机号,可以从bindgetphonenumber回调中获取到⽤⼾信息, 具体说明
getUserInfo获取用户信息,可以从bindgetuserinfo回调中获取到用户信息
launchApp打开APP,可以通过app-parameter属性设定向APP传的参数具体说明
openSetting打开授权设置页
feedback打开“意见反馈”页面,⽤⼾可提交反馈内容并上传日志,开发者可以登 录小程序管理后台后进⼊左侧菜单“客服反馈”页面获取到反馈内容

open-type 的contact的实现流程

  1. 将小程序 的 appid 由测试号改为自己的 appid
  2. 登录微信小程序官网,添加 客服 – 微信
  3. . 为了方便演示,准备了两个账号
    1. 普通用户
    2. 客服-微信
  4. 操作
<!-- 

  button 开发能力
  open-type:
  1 contact 直接打开  客服对话功能  需要在微信小程序的后台配置   只能够通过真机调试来打开 
  2 share 转发当前的小程序 到微信朋友中   不能把小程序 分享到 朋友圈 
  3 getPhoneNumber 获取当前用户的手机号码信息 结合一个事件来使用  不是企业的小程序账号 没有权限来获取用户的手机号码 
    1 绑定一个事件 bindgetphonenumber 
    2 在事件的回调函数中  通过参数来获取信息 
    3 获取到的信息  已经加密过了 
      需要用户自己待见小程序的后台服务器,在后台服务器中进行解析 手机号码,返回到小程序中 就可以看到信息了
  4 getUserInfo 获取当前用户的个人信息
    1 使用方法 类似 获取用户的手机号码
    2 可以直接获取 不存在加密的字段 
  5 launchApp 在小程序当中 直接打开 app
    1 需要现在 app中 通过app的某个链接 打开 小程序
    2 在小程序 中 再通过 这个功能 重新打开 app
    3 找到 京东的app 和 京东的小程序  
  6 openSetting 打开小程序内置的 授权页面
    1 授权页面中 只会出现 用户曾经点击过的 权限 
  7 feedback 打开 小程序内置的 意见反馈页面 
    1 只能够通过真机调试来打开 
  -->
<button open-type="contact">contact</button>
<button open-type="share">share</button>
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">getPhoneNumber</button>
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">getUserInfo</button>
<button open-type="launchApp">launchApp</button>
<button open-type="openSetting">openSetting</button>
<button open-type="feedback">feedback</button>

10.8.icon

属性类型默认值必填说明
typestringicon的类型,有效值:success, success_no_circle, info, warn, waiting, cancel, download, search, clear
sizenumber/string23icon的⼤⼩
colorstringicon的颜⾊,同css的color
  1. WXML

    <view class="group">
      <block wx:for="{{iconSize}}">
        <icon type="success" size="{{item}}"/>
      </block>
    </view>
    <view class="group">
      <block wx:for="{{iconType}}">
        <icon type="{{item}}" size="40"/>
      </block>
    </view>
    <view class="group">
      <block wx:for="{{iconColor}}">
        <icon type="success" size="40" color="{{item}}"/>
      </block>
    </view>
    
    
  2. JS

    Page({
      data: {
        iconSize: [20, 30, 40, 50, 60, 70],
        iconType: [
          'success', 'success_no_circle', 'info', 'warn', 'waiting', 'cancel',
    'download', 'search', 'clear'
       ],
        iconColor: [
          'red', 'orange', 'yellow', 'green', 'rgb(0,255,255)', 'blue', 'purple'
       ],
     }
    })
    
    

10.9.radio

可以通过 color属性来修改颜色

需要搭配radio-group⼀起使用

  1. WXML

    <!-- 
      radio 单选框
      1 radio标签 必须要和 父元素 radio-group来使用
      2 value 选中的单选框的值 
      3 需要给 radio-group 绑定 change事件 
      4 需要在页面中显示 选中的值
     -->
     <radio-group bindchange="handleChange">
       <radio color="red" value="male"></radio>
       <radio color="red" value="female" ></radio>
     </radio-group>
    
     <view>您选中的是:{{gender}}</view>
    
  2. javascript

    // pages/demo15/demo15.js
    Page({
      data: {
        gender: ""
      },
      handleChange(e){
        // 1 获取单选框中的值
        let gender=e.detail.value;
        // 2 把值 赋值给 data中的数据
        this.setData({
          // gender:gender
          gender
        })
      }
    })
    
  3. 效果

10.10.checkbox

可以通过 color属性来修改颜色

需要搭配radio-group⼀起使用

11.自定义组件

类似vue或者react中的自定义组件

小程序允许我们使用自定义组件的方式来构建页面。

11.1.创建自定义组件

类似于页面,一个自定义组件由 json、wxml、wxss、js 4个文件组成

可以在微信开发者工具中的根目录下快速创建组件的文件结构components文件夹-》创建一个和自定义组件名相同的文件夹componentsName,在该文件夹上点击右键<新建Component>并输入componentsName就创建好相应的组件的需要的文件

在⽂件夹内 components/Tabs ,创建组件 名为Tabs

11.1.1.声明组件

⾸先需要在组件的 json 文件中进行自定义组件声明

Tabs.json

{
  "component": true,
  "usingComponents": {}
}

11.1.2.编辑组件

同时,还要在组件的 wxml 文件中编写组件模板,在 wxss 文件中加入组件样式 slot 表⽰插槽,类似vue中的slot

Tabs.wxml

<!-- 这是自定义组件的内部WXML结构 -->
<view class="inner">
 {{innerText}}
    <slot></slot>
</view>

在组件的 wxss ⽂件中编写样式

注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。

Tabs.wxss

/* 这里的样式只应用于这个自定义组件 */
.inner {
  color: red;
}

Tabs.json

{
  "component": true,//标注这是一个component
  "usingComponents": {}//如果引用其他组件,在这里添加即可
}

11.1.3.注册组件

在组件的 js ⽂件中,需要使⽤ Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法

Tab.js

Component({
  properties: {
    // 这里定义了innerText属性,属性值可以在组件使用时指定
    innerText: {
      // 期望要的数据是 string类型
      type: String,
      value: 'default value',
    }
  },
   data: {
     // 这里是一些组件内部数据
     someData: {}
  },
   methods: {
     // 这里是一个自定义方法
     customMethod: function(){}
  }
 })

11.2. 声明引入自定义组件

首先要在页面的 json 文件中进行引用声明。还要提供对应的组件名和组件路径。

index.json

{   
   "usingComponents": {
     "Tabs":"../../components/Tabs/Tabs"
  }
 }

11.3. 页面中使用自定义组件

index.wxml

<Tabs></Tabs>

效果:

11.4.其他属性

11.5. 定义段与示例方法

Component 构造器可用于定义组件,调⽤ Component 构造器时可以指定组件的属性、数据、方法等。

定义段类型是否必填描述
propertiesObject Map组件的对外属性,是属性名到属性设置的映射表,参⻅下⽂
dataObject组件的内部数据,和 properties ⼀同⽤于组件的模板渲 染
observersObject组件数据字段监听器,⽤于监听 properties 和 data 的变 化,参见数据监听器
methodsObject组件的方法,包括事件响应函数和任意的⾃定义⽅法,关于 事件响应函数的使用,参见组件事件
createdFunction组件⽣命周期函数,在组件实例刚刚被创建时执行,注意此 时不能调⽤ setData ,参见组件生命周期
attachedFunction组件⽣命周期函数,在组件实例进⼊页面节点树时执行,参见组件生命周期
readyFunction组件⽣命周期函数,在组件布局完成后执行,参见组件⽣命周期
movedFunction组件生命周期函数,在组件实例被移动到节点树另⼀个位置 时执行,参见组件生命周期
detachedFunction组件生命周期函数,在组件实例被从页面节点树移除时执 行,参见组件生命周期

11.6.组件-自定义组件传参

  1. ⽗组件通过属性的⽅式给⼦组件传递参数
  2. ⼦组件通过事件的⽅式向⽗组件传递参数

11.6.1. 过程

  1. ⽗组件 把数据 {{tabs}} 传递到 ⼦组件的 tabItems 属性中
  2. ⽗组件 监听 onMyTab 事件
  3. ⼦组件 触发 bindmytap 中的 mytap 事件
    1. ⾃定义组件触发事件时,需要使⽤ triggerEvent ⽅法,指定 事件名 、 detail 对象
  4. ⽗ -> ⼦ 动态传值 this.selectComponent("#tabs");

父组件代码

子组件代码

11.7.示例

  1. 要求

  2. 自定义组件components(子组件)

    • 组件Tab的tab.wxml

      
      <view class="tabs">
        <view class="tabs_title">
          <!-- <view class="title_item active">首页</view>
          <view class="title_item">原创</view>
          <view class="title_item">分类</view>
          <view class="title_item">关于</view> -->
      
          <view 
          wx:for="{{tabs}}"
          wx:key="id"
          class="title_item {{item.isActive?'active':''}}"
          bindtap="hanldeItemTap"
          data-index="{{index}}"
          >
          {{item.name}}
        </view>
        </view>
        <view class="tabs_content">
          <!-- 
            slot 标签 其实就是一个占位符 插槽
            等到 父组件调用 子组件的时候 再传递 标签过来 最终 这些被传递的标签
            就会替换 slot 插槽的位置 
           -->
          <slot></slot>
        </view>
      </view>
      
    • 组件Tab的tab.js

      // components/Tabs.js
      Component({
        /**
         * 里面存放的是 要从父组件中接收的数据
         */
        properties: {
          // 要接收的数据的名称
          // aaa:{
          //   // type  要接收的数据的类型 
          //   type:String,
          //   // value  默认值
          //   value:""
          // }
          tabs:{
            type:Array,
            value:[]
          }
        },
      
        /**
         * 组件的初始数据
         */
        data: {
          // tabs
        },
        /* 
        1 页面.js 文件中 存放事件回调函数的时候 存放在data同层级下!!!
        2 组件.js 文件中 存放事件回调函数的时候 必须要存在在 methods中!!!
         */
       
      
        methods: {
          hanldeItemTap(e){
            /* 
            1 绑定点击事件  需要在methods中绑定
            2 获取被点击的索引 
            3 获取原数组 
            4 对数组循环
              1 给每一个循环性 选中属性 改为 false
              2 给 当前的索引的 项 添加激活选中效果就可以了!!!
      
             
             5 点击事件触发的时候 
                触发父组件中的自定义事件 同时传递数据给  父组件  
                this.triggerEvent("父组件自定义事件的名称",要传递的参数)
             */
      
            //  2 获取索引
            const {index}=e.currentTarget.dataset;
            // 5 触发父组件中的自定义事件 同时传递数据给  
            this.triggerEvent("itemChange",{index});
            // 3 获取data中的数组
            // 解构  对 复杂类型进行结构的时候 复制了一份 变量的引用而已
            // 最严谨的做法 重新拷贝一份 数组,再对这个数组的备份进行处理,
            // let tabs=JSON.parse(JSON.stringify(this.data.tabs));
            // 不要直接修改 this.data.数据 
            // let {tabs}=this.data;
            // let tabs=this.data;
            // 4 循环数组
            // [].forEach 遍历数组 遍历数组的时候 修改了 v ,也会导致源数组被修改
            // tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
      
            // this.setData({
              // tabs
            // })
          }
        }
      })
      
    • 组件Tab的Tab.wxss

      .tabs_title{
        display: flex;
        padding: 10rpx 0;
      }
      .title_item{
        flex: 1;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      .active{
        color:red;
        border-bottom: 5rpx solid currentColor;
      }
      
    • 组件Tab的Tab.json

      {
        "component": true,
        "usingComponents": {}
      }
      
  3. 在页面(父组件)中使用组件Tab(子组件)

    • 引入组件Page.json

      {
        "usingComponents": {
          "Tabs":"../../components/Tabs/Tabs"
        }
      }
      
    • Page.js

      // pages/demo17/demo18.js
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
      
          tabs: [
            {
              id: 0,
              name: "首页",
              isActive: true
            },
            {
              id: 1,
              name: "原创",
              isActive: false
            }
            ,
            {
              id: 2,
              name: "分类",
              isActive: false
            }
            ,
            {
              id: 3,
              name: "关于",
              isActive: false
            }
          ]
      
        },
      
        // 自定义事件 用来接收子组件传递的数据的
        handleItemChange(e) {
          // 接收传递过来的参数
          const { index } = e.detail;
          let { tabs } = this.data;
          tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
          this.setData({
            tabs
          })
        }
      })
      
    • Page.wxml

      <!-- 
        1 父组件(页面) 向子组件 传递数据 通过 标签属性的方式来传递
          1 在子组件上进行接收
          2 把这个数据当成是data中的数据直接用即可
        2 子向父传递数据 通过事件的方式传递
          1 在子组件的标签上加入一个 自定义事件
        
       -->
      <Tabs tabs="{{tabs}}" binditemChange="handleItemChange" >
      <block wx:if="{{tabs[0].isActive}}">0 </block>
      <block wx:elif="{{tabs[1].isActive}}">1 </block>
      <block wx:elif="{{tabs[2].isActive}}">2 </block>
      <block wx:else>3</block>
      </Tabs>
      

11.7. 小结

  1. 标签名 是 中划线的⽅式
  2. 属性的⽅式 也是要中划线的⽅式
  3. 其他情况可以使⽤驼峰命名
    1. 组件的⽂件名如 myHeader.js 的等
    2. 组件内的要接收的属性名 如 innerText
  4. 更多参考文档

12.小程序生命周期

分为应用生命周期页面生命周期

关于小程序前后台的定义和小程序的运行机制,请参考运行机制章节。

12.1. 应用生命周期

应用指小程序的入口文件,也就是app.js

属性类型必填说明
onLaunchfunction监听小程序初始化,应用第一次启动就会触发的事件(例如在应用第一次启动的时候,获取用户的个人信息)。
onShowfunction监听小程序启动或切前台,应用被用户看到时候触发(例如应用切换启动时,页面效果重置)。
onHidefunction监听小程序切后台,应用被隐藏的时候触发(暂停或者清除定时器触发)。
onErrorfunction错误监听函数,当应用代码发生错误的时候会触发,会有一个err的错误信息参数(在应用发生代码错误触发,可以通过异步请求将错误信息发送给后台)。
onPageNotFoundfunction页面不存在监听函数,页面找不到的时候报错,相当于onError中的一种()。
//app.js
App({
  //  1 应用第一次启动的就会触发的事件  
  onLaunch() {
    //  在应用第一次启动的时候 获取用户的个人信息 
    // console.log("onLaunch");
    // aabbcc

    // js的方式来跳转 不能触发 onPageNotFound
    // wx.navigateTo({
    //   url: '/11/22/33'
    // });
      
  },

  // 2 应用 被用户看到 
  onShow(){
    // 对应用的数据或者页面效果 重置 
    // console.log("onShow");
  },
  // 3 应用 被隐藏了 
  onHide(){
    // 暂停或者清除定时器 
    // console.log("Hide");
  },
  // 4 应用的代码发生了报错的时候 就会触发
  onError(err){
    // 在应用发生代码报错的时候,收集用户的错误信息,通过异步请求 将错误的信息发送后台去
    // console.log("onError");
    // console.log(err);
  },
  // 5 页面找不到就会触发 
  //  应用第一次启动的时候,如果找不到第一个入口页面 才会触发
  onPageNotFound(){
    // 如果页面不存在了 通过js的方式来重新跳转页面 重新跳到第二个首页
    // 不能跳到tabbar页面导航组件类似  
    wx.navigateTo({
      url: '/pages/demo09/demo09' 
    });  
      
    // console.log("onPageNotFound");
  }
})

12.2.页面生命周期

属性类型说明
dataObject页面的初始数据
onLoadfunction页面加载完毕触发,一般在这个函数发送一些异步请求来初始化页面数据
onShowfunction页面显示时触发
onReadyfunction页面初次渲染完毕后触发
onHidefunction页面隐藏的时候触发,应用隐藏以及跳转到其他页面时触发
onUnloadfunction页面卸载的时候触发,即关闭当前页面,跳转其他页面。(可参考10.5navigator中opne-type为关闭的时候)
onPullDownRefreshfunction监听用户下拉动作触发,在app.js的window中设置。可以进行页面数据属性
onReachBottomfunction页面上拉触底事件的处理函数,当页面数据足够多,需要往上拉到底部的时候触发。可以用来加载下一页数据。
onShareAppMessagefunction用户点击右上角转发时触发
onPageScrollfunction页面滚动触发事件的处理函数
onResizefunction页面尺寸改变时触发,详见响应显示区域变化,横屏,竖屏的时候发生。如果要可以发生横屏竖屏在page.json中添加"pageOrientation": “auto”,或者在app.json中设置,所有的页面都可以。
onTabItemTapfunction当前是tab页时,点击tab时触发

Page.js

// pages/demo18/demo18.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log("onLoad");
    // onLoad发送异步请求来初始化页面数据 
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    console.log("onShow");
  },
  /**
    * 生命周期函数--监听页面初次渲染完成
    */
  onReady: function () {
    console.log("onReady");
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
    console.log("onHide");
  },

  /**
   * 生命周期函数--监听页面卸载 也是可以通过点击超链接来演示 
   * 
   */
  onUnload: function () {
    console.log("onUnload");
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
    console.log("onPullDownRefresh");
    // 页面的数据 或者效果 重新 刷新
  },

  /**
   * 页面上拉触底事件的处理函数
   * 需要让页面 出现上下滚动才行 
   */
  onReachBottom: function () {
    console.log("onReachBottom");
    // 上拉加载下一页数据 
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
    console.log("onShareAppMessage");
  },
  /**
   * 页面滚动 就可以触发 
   */
  onPageScroll(){
    console.log("onPageScroll");
  },
  /**
   * 页面的尺寸发生改变的时候 触发
   * 小程序 发生了 横屏竖屏 切换的时候触发 
   */
  onResize(){
    console.log("onResize");
  },
  /**
   * 1 必须要求当前页面也是tabbar页面
   * 2 点击的自己的tab item的时候才触发
   */
  onTabItemTap(){
    console.log("onTabItemTap");
  }
})

12.3. 页面生命周期图解

13.补充说明

13.1微信小程序版本发布

13.1.1.设置小程序的APPID

13.1.2.在微信公众平台设置小程序访问的后台地址(http协议)

  • 小程序访问的后台程序地址

  • 在微信公众平台设置访问地址

13.1.3.关闭不进行Https协议以及证书的校验

13.1.4.上传

13.1.5.提交审批

13.2.版本测试说明

当版本发布后现场进行手机端测试时,一定要将手机端的小程序删除后重新搜索添加到手机上,再进行测试

13.3.小程序开发常见错误

13.3.1.微信小程序开发出现:Unexpected token o in JSON at position 1;at api request success callback function异常

该错误一般出现在处理返回JSON数据时

RN解析数据时报错,原因是返回的数据已经是object格式

解决方案:

  1. JSON.stringify(对象);把对象转String
  2. 2.JSON.parse();把string转对象

示例:

 App.request.loadModInfo(App.globalData.IPURL, param, function (response) {
    var result = JSON.stringify(response);
    result = JSON.parse(result);
    console.log(result);
    if(result.CODE=="00"){
        that.setData({
            tab: result.MODLIST
        })
    }        
})

13.3.2.微信小程序开发出现:Cannot read property ‘setData’ of undefined;at api request success callback

作用域问题——回调函数中的作用域已经脱离了调用函数了,因此需要在回调函数外边把this赋给一个新的变量才可以了。
此处将this赋值给变量self

loadModInfo :function(){
    var self = this
    var param ={
        "MOD_ID":"WAK",
        "FYDM":App.globalData.FYDM
    }
    console.log(param);
    App.request.loadModInfo(App.globalData.IPURL, param, function (response) {
        var result = JSON.stringify(response);
        result = JSON.parse(result);
        console.log(result);
        if(result.CODE=="00"){
            that.setData({
                tab: result.MODLIST
            })
        }        
    })
}

13.4.小程序访问后台网络数据建议格式

13.4.1.涉及文件

13.4.1.在app.js定义后台请求地址IPURL

var net_js = require('./net/net')
App({
    globalData: {
        userInfo: null,
        CID: "0000",
        // 示例:IPURL:'http://ip:port/xszfweb/'
        IPURL: 'http://192.168.1.169:8088/xszfweb/',
        FYDM: "320000",
        //订阅消息模板
        SubscribeMsgTemplate:['F9eVJkbsidSFWadWAdXsj7Cjlzxg_CbtCc5e3CyOK1g']
    },
    request: {
        checkUserYhdm:net_js.checkUserYhdm,
        getUserOpenid:net_js.getUserOpenid,
        bindUser:net_js.bindUser,
        loadModInfo:net_js.loadModInfo,
    }
})

13.4.2.定义net.js的工具方法getUserOpenid

module.exports创建接口,便于引用

var Base64 = require('../utils/base64Decode');
/**
 * 1.根据code,appid,fydm获取用户openid
 * @param {*} ip :请求地址
 * @param {*} param :携带参数;1.code.appid,3.fydm
 * @param {*} callback :回调函数
 */
function getUserOpenid(ip,param,callback){
    var data={"method":"getOpenid","body":param};
    postRequest(ip+"web/wakTransmit", data, "application/json", function (res) {
        return typeof callback == "function" && callback(res)
    })
}
/**
 * 发送post请求
 * @param {*} ip 
 * @param {*} param 
 * @param {*} content_type 
 * @param {*} callback 
 */
function postRequest(ip, param, content_type, callback) {
    wx.request({
        url: ip,
        header: {
            'Content-Type': content_type
        },
        method: "POST",
        data: param,
        async:false,
        success: function (res) {
            return typeof callback == "function" && callback(res.data)
        },
        fail: function (res) {
            var msg = res.errMsg
            var err = {
                code: '1',
                message: msg
            }
            return typeof callback == "function" && callback(err)
        }
    })
}

module.exports = {
    getUserOpenid: getUserOpenid,
}

13.4.3.在登录页面的login.js使用该方法

引入getApp(),通过App.request.checkUserYhdm调用

var Base64 = require('../../utils/base64Decode.js');
const App = getApp();
Page({
    data: {
        xm: '',
        sfzh: '',
    },
    /**
     * 根据用户的身份信息以及openid开始验证用户是否已绑定用户
     */
    verifyUser: function(openid){
        const xm = this.data.xm;
        const sfzh = this.data.sfzh;
        var param = {
            "yhxm":xm,
            "sfzhm":sfzh,
            "openid":openid
        }
        App.request.checkUserYhdm(App.globalData.IPURL,param,function(response){
            var result = JSON.stringify(response);
            result = JSON.parse(result);
            if(result.code=='00'){
                var userInfo = {
                    "xm": xm,
                    "sfzh": sfzh,
                    "yhdm": result.userinfo.yhdm,
                    "openid": openid,
                    "dwdm": result.userinfo.dwdm,
                }
                wx.setStorageSync("userInfos", userInfo)
                wx.reLaunch({
                    url: "/pages/index/index",
                })
            }
        })
    },
})

13.5.setData函数设置复杂数据

13.5.1.设置类似map类型数据

Page({
    data: {
        userInfo:{},
    },
    
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        //页面加载是接受数据,设置参数
        this.setData({
            userInfo: {
                xm: options.xm,
                sfzh: options.sfzh,
                openid:options.opendid
            },
        })
    },
})

13.5.2.设置类似list数据

直接将json中返回的list赋值即可

Page({
    /**
     * 页面的初始数据
     */
    data: {
        tab:[]
        //测试数据
        //tab: [
             //     {"name": "我的案款","url": "web/login","info": "浏览本人办理的案件款项","code": "1"}, 				
             //   	{"name":"我的审批","url": "web/login", "info": "本人的待审批信息","code": "2"}
     		 //]
    },
     /**
     * 初始化时获取页面的功能模块信息
     */
    loadModInfo :function(){
        var self = this
        var param ={
            "mod_id":"WAK",
            "fydm":App.globalData.FYDM
        }
        console.log(param);
        App.request.loadModInfo(App.globalData.IPURL, param, function (response) {
            var result = JSON.stringify(response);
            result = JSON.parse(result);
            if(result.code=="00"){
                //直接将json中返回的list赋值即可
                self.setData({
                    tab: result.modlist
                })
            }        
        })
    }
}

13.6.消息订阅接口

13.7.获取openid

获取openid首先要获取通过wx.login()获取code,然后code获取appid

13.7.1.小程序端通过wx.login获取code

获取openid首先要获取通过wx.login()获取code

checkYhdm: function(){
        var self = this
        //1.通过微信获取code
        wx.login({
            success:function(res){
                //2.根据获取的code,appid,fydm调用后台服务器去获取openid
                var code = res.code;
                var data={
                    "code": code,
                    "appid": wx.getAccountInfoSync().miniProgram.appId,
                    "fydm":App.globalData.FYDM
                };
                App.request.getUserOpenid(App.globalData.IPURL,data,function(response){
                    var result = JSON.stringify(response);
                    result = JSON.parse(result);
                    if(result.code=="00"){
                        //3.当获取openid成功后进行绑定操作
                        self.verifyUser(result.openid)
                    }else{
                        wx.showModal({
                            title: '温馨提示',
                            content: "openid获取失败,请联系管理员",
                            showCancel: false
                        })
                    }
                })
            }
        })
    },

13.7.2.将code和appid传递给后台服务器请求微信接口获取openid

public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {
        WxMaConfig config = this.getWxMaConfig();
        Map<String, String> params = new HashMap(8);
        params.put("appid", config.getAppid());
        params.put("secret", config.getSecret());
        params.put("js_code", jsCode);
        params.put("grant_type", "authorization_code");
        String result = this.get("https://api.weixin.qq.com/sns/jscode2session", Joiner.on("&").withKeyValueSeparator("=").join(params));
        return WxMaJscode2SessionResult.fromJson(result);
    }

13.8.小程序之间的跳转

13.8.1.原小程序通过准备跳转到其他小程序

通过wx.navigateToMiniProgram完成跳转

  • appId是目标小程序的APPID
  • path是目标小程序的页面,如果需要携带参数,在path后加?param1=xxxx&param2=yyyy
//跳转博思支付小程序完成支付
payBosiRequest: function(res){
    if (res.data.success == true) {
        var extraInfo = JSON.parse(res.data.extraInfo);
        wx.navigateToMiniProgram({
            appId: extraInfo.miniprogram.appid,
            path: extraInfo.miniprogram.pagepath,
            success(res) {
                console.log("跳转博思支付成功");
            }
        })
    }
}

13.8.2.目标小程序的接收参数并加载页面

 /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    this.setData({
      zfje: 0.00
    })
    var obj = wx.getLaunchOptionsSync()
    var userInfo = obj.referrerInfo.extraData
    var appId = obj.referrerInfo.appId
    if (appId != undefined && appId.length > 0) {
      if (userInfo != undefined) {
        var xm = userInfo.xm
        var sfzh = userInfo.sfzh
        if (xm != undefined && xm.length > 0 && sfzh != undefined && sfzh.length > 0) {
          wx.setStorageSync("userInfos", userInfo)
          this.getWjYjDzfRequest()
        } else {
          wx.navigateTo({
            url: '/pages/login/login',
          })
        }
      } else {
        wx.navigateTo({
          url: '/pages/login/login',
        })
      }
    } else {
      this.getWjYjDzfRequest()
    }
  },

13.9.微信小程序嵌套H5页面

13.9.1.定义小程序的H5容器container.js

对于调用H5页面使用微信小程序的H5容器,对传递来的参数先使用base64编码,避免链接中的问号等情况造成错误

const App = getApp();
var Base64 = require('../../utils/base64Decode.js');
Page({
    /**
     * 页面的初始数据
     */
    data: {
        urlstr:""
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        //页面加载时
        //1.获取服务后台地址+options携带的h5页面路径+缓存的必要参数拼接页面地址
        var userInfos = wx.getStorageSync("userInfos");
        this.setData({
            urlstr: App.globalData.IPURL + Base64.decode(options.pageUrl)+"?yhdm="+userInfos.yhdm
        })
    },
})

13.9.2.定义小程序的H5容器container.wxml

<web-view src="{{urlstr}}"></web-view>

container.wxss和container.json不需要任何配置,省略即可

13.9.3.其他页面跳转到该页面

通过navigator标签携带参数跳转到container页面,携带参数通过onLoad的options接受处理

<!-- 4.根据传入的数据动态显示宫格(一行两列图标)信息 -->
<view class="weui-grids">
    <view class="weui-grid" wx:for="{{tab}}" wx:key="gndm">
        <navigator url="/pages/container/container?pageUrl={{item.url}}&openid={{openid}}&yhdm={{yhdm}}">
            <view class='weui_grid_bg'>
                <!-- 4.1.显示功能模块log -->
                <view class="weui_grid_icon">
                    <image src="{{item.icon}}" mode="scaleToFill" />
                </view>
                <!-- 4.2.显示功能模块名称 -->
                <text class="weui_grid_label">{{item.name}}</text>
                <!-- 4.3.显示功能模块说明 -->
                <text class="weui_grid_info">{{item.info}}</text>
            </view>
        </navigator>
    </view>
</view>

13.10.H5.页面的事件携带参数跳转到微信小程序

13.10.1.H5.页面引入相关的JS文件

<script type="text/javascript" th:src="@{/static/js/jweixin-1.3.2.js}"></script>

13.10.2.H5.页面JS函数跳转到微信小程序页面

function downloadSp(id) {
    if("miniProgram" == pageType){
        var wsAhdm = $.trim(id.split("_", -1)[0]);
        var xh = $.trim(id.split("_", -1)[1]);
        if (wsAhdm == "" || xh == "") {
            layerMsg("文书尚未生成");
            return;
        }
        wx.miniProgram.navigateTo({url: "/pages/downloadFile/downloadFile?ahdm=" +wsAhdm + "&jzxh=" + xh});
    }else {
      //略
    }
}

13.10.3.微信小程序准备downloadFile页面

  1. downloadFile.js

    // pages/downloadFile/downloadFile.js
    const App = getApp();
    Page({
        /**     
         * 页面的初始数据     
         */
        data: {},
        /**     
         * 生命周期函数--监听页面加载     
         */
        onLoad: function (options) {
            var ahdm = options.ahdm;
            var jzxh = options.jzxh;
            console.log("ahdm:" + ahdm);
            wx.downloadFile({
                url: App.globalData.IPURL + 'wak/downloadSp?ahdm=' + ahdm + '&jzxh=' + jzxh,
                success: function (res) {
                    wx.saveFile({
                        tempFilePath: res.tempFilePath,
                        success: function (res2) {
                            wx.openDocument({
                                filePath: res2.savedFilePath,
                                success: function (res) {}
                            })
                        }
                    })
                }
            })
            wx.navigateBack();
        }
    })
    
  2. downloadFile.wxml

    <view></view>
    

13.11.定义全局变量

一般设置全局变量做到修改时全部修改,例如后台服务器地址

13.11.1.在微信小程序的app.js定义全局变量

globalData: {
    // 示例:IPURL:'http://ip:port/xszfweb/'
    IPURL: 'http://192.168.1.169:8088/xszfweb/',
    //订阅消息模板
    SubscribeMsgTemplate:['F9eVJkbsidSFWadWAdXsj7Cjlzxg_CbtCc5e3CyOK1g']
},

13.11.2.在需要使用的页面的js中使用全局变量

  1. 首先引用getApp()赋值给App
  2. 然后通过变量App使用获取全局变量App.globalData.IPURL
const App = getApp();
Page({
    /**
     * 初始化时获取页面的功能模块信息
     */
    loadModInfo :function(){
        var self = this
        var param ={
            "mod_id":"WAK",
            "fydm":App.globalData.FYDM
        }
        App.request.loadModInfo(App.globalData.IPURL, param, function (response) {
            var result = JSON.stringify(response);
            result = JSON.parse(result);
            if(result.code=="00"){
                self.setData({
                    tab: result.modlist
                })
            }        
        })
    }
})

13.12.获取小程序APPID

wx.getAccountInfoSync().miniProgram.appId

13.13.注意请求异步性问题

function sendCheckMsg(param){
    var result="error";
    App.request.noticeCheckRes(App.globalData.IPURL, param, function (response) {
        var msg = JSON.stringify(response);
        msg = JSON.parse(msg);
        console.log(msg);
        if(msg.code=="00"){
            result = "succ";
        }   
    })
    return result;
}

当别的方法调用该函数,当noticeCheckRes调用成功时,因为其函数的请求的异步性,return函数已经执行,故返回的还是error

13.14.文件下载

13.14.1.downloadFile.wxml

<view>
	<view class="btn" bindtap="load">下载</view>
    <loading hidden="{{  loadingHidden }}">加载中...</loading>
</view>

13.14.2.downloadFile.js

Page({
    /**
     * 页面的初始数据
     */
    data: {
        loadingHidden: "true"
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {},
    load: function () {
        this.setData({
            loadingHidden: false
        })
        let self = this;
        wx.downloadFile({
            url: 'http://192.168.1.160:8088/xszfweb/wak/downloadSp?ahdm=115020201002000050&jzxh=0052&ver=1600409402056',
            success: function (res) {
                var filePath = res.tempFilePath;
                console.log(res)
                //页面显示加载动画
                wx.openDocument({
                    filePath: filePath,
                    success: function (res) {
                        self.setData({
                            loadingHidden: true
                        })
                        console.log('打开文档成功')
                    }
                })
            }
        })
    }
})

13.15.在图标加上数量提示

在图标上醒目的数字提示,告知用户有待办事项

13.15.1.index.wxml

<view class="weui-grid" wx:for="{{tab}}" wx:key="gndm">
    <!-- 4.1.当页面为H5页面时(对应T_MODULE_ONLINE的type字段为01),跳转到container(H5页面容器),打开H5页面 -->
    <view wx:if="{{item.type=='01'}}">
        <navigator url="/pages/container/container?pageUrl={{item.url}}">
            <view class='weui_grid_bg'>
                <!-- 4.1.1.显示功能模块log -->
                <view class="weui_grid_icon">
                    <image src="{{item.icon}}" mode="scaleToFill" />
                    <!-- 4.1.2.针对需要在图片右上角显示提示数字的设置,例如未审批的流程数-->
                    <text class="span"
                          wx:if="{{(item.mark=='true')&&(item.digital>0)&&(item.digital<=99)}}">{{item.digital}}</text>
                    <text class="span" wx:elif="{{(item.mark=='true')&&(item.digital>99)}}">99+</text>
                </view>
                <!-- 4.1.3.显示功能模块名称 -->
                <text class="weui_grid_label">{{item.name}}</text>
                <!-- 4.1.4.显示功能模块说明 -->
                <text class="weui_grid_info">{{item.info}}</text>
            </view>
        </navigator>
    </view>
</view>

13.15.2.index.js

保证item中包含digital参数,大于0即可

13.15.3.index.wxss

.weui-grid .span {
    position: absolute;
    /* 根据需要调整top和right */
    top: 0rpx;
    right: 85rpx;
    display: inline-block;
    padding: 4rpx 10rpx;
    min-width: 16rpx;
    border-radius: 36rpx;
    background-color: #fa5151;
    /* background-color: var(--weui-RED); */
    color: #fff;
    line-height: 1.2;
    text-align: center;
    font-size: 24rpx;
}

13.16.在H5页面增加排序图片

13.16.1.示例

31085229571

13.16.2.实现

  1. 引入对应的layer的js文件和css文件

    <script th:src="@{/static/ext/layui/layui.js}"></script>
    <script th:src="@{/static/ext/layer_mobile/layer.js}"></script>
    <link rel="stylesheet" th:href="@{/static/ext/layui/css/layui.css}" media="all">
    <style type="text/css">
        html, body {
            width: 100%;
            height: 100%;
        }
    
        .arrUp {
            width: 0;
            height: 0;
            border: 8px solid transparent;
            border-bottom-color: #ccc;
            cursor: pointer;
        }
    
        .arrDown {
            width: 0;
            height: 0;
            border: 8px solid transparent;
            border-top-color: #ccc;
            margin-top: 5px;
            cursor: pointer;
        }
    </style>
    
  2. H5

    <div class="arr" style="height: 0.70rem;width: 100%">
        <table style="width: 100%">
            <tr>
                <td style="width: 25%;text-align: center">已缴金额</td>
                <td style="width: 25%;text-align: left">
                    <div class="arrUp" name="yjje" id="TKZE_ASC"></div>
                    <div class="arrDown" name="yjje" id="TKZE_DESC"></div>
                </td>
                <td style="width: 25%;text-align: center">可退金额</td>
                <td style="width: 25%;text-align: left">
                    <div class="arrUp" name="tkje" id="WTKZE_ASC"></div>
                    <div class="arrDown" name="tkje" id="WTKZE_DESC"></div>
                </td>
            </tr>
        </table>
    </div>
    <input type="hidden" value="" id="sortType"/>
    <input type="hidden" value="ASC" id="sortDirection"/>
    
  3. JS函数

    $(document).ready(function () {
        $("div[name='yjje']").on("click", function () {
            var sortDirection = $('#sortDirection').val();
            if ("ASC" === sortDirection) {
                $(".arrUp").css("border-bottom-color", '')
                $(".arrDown").css("border-top-color", '')
                $("#TKZE_DESC").css("border-top-color", "#3176ee");
                sort("TKZE_DESC");
            } else {
                $(".arrUp").css("border-bottom-color", '')
                $(".arrDown").css("border-top-color", "")
                $("#TKZE_ASC").css("border-bottom-color", "#3176ee");
                sort("TKZE_ASC");
            }
        })
        $("div[name='tkje']").on("click", function () {
            var sortDirection = $('#sortDirection').val();
            if ("ASC" == sortDirection) {
                $(".arrUp").css("border-bottom-color", '')
                $(".arrDown").css("border-top-color", '')
                $("#WTKZE_DESC").css("border-top-color", "#3176ee");
                sort("WTKZE_DESC");
            } else {
                $(".arrUp").css("border-bottom-color", '')
                $(".arrDown").css("border-top-color", "")
                $("#WTKZE_ASC").css("border-bottom-color", "#3176ee");
                sort("WTKZE_ASC");
            }
        })
        searchData('init');
    });
    function sort(id) {
        var arr = id.split('_');
        $('#sortType').val(arr[0]);
        $('#sortDirection').val(arr[1]);
        search('refreshAll');
    }
    function search(optype) {
        var rowsNum = $("#rowsNum").val();
        var currentPage = Number($("#currentPage").text());
        var totalPage = $("#totalPage").text();
        if ("pageDown" == optype && currentPage < totalPage) {
            currentPage += 1;
        } else if ("pageUp" == optype && currentPage != 1) {
            currentPage -= 1;
        } else if ("refreshAll"==optype){
            //针对输入新的查询内容,全部数据刷新的操作
            currentPage = 1;
        } else if ("refresh" == optype) {
            //针对上拉只刷新刷新本页数据
        }
        var param = {
            "yhdm": $("#yhdm").val(),
            "ahorje": $("#ahorje").val(),
            "pagenum": rowsNum,
            "curpage": (currentPage - 1),
            "sortType": $('#sortType').val(),
            "sortDirection": $('#sortDirection').val()
        };
        sendMsg(param);
    }
    

    sortType,sortDirection存储参数

13.17.在首页生成九宫格

一般首页中需要展示为九宫格,或者六宫格展示所有的功能信息。点击功能一般为跳转到H5页面,打开小程序的另一个页面,或者调用小程序的函数等。故需要对不同情况进行不同的配置。

31104419763

13.17.1.在数据库中配置不同的功能模块

31102728870

建表SQL:

CREATE TABLE T_MODULE_ONLINE (
	LSH varchar(10) NOT NULL,
	GNDM varchar(10) NOT NULL,
	GNMC varchar(20) NOT NULL,
	GN_URL varchar(250) NULL,
	IMG_URL varchar(250) NULL,
	PXH int NULL,
	STATE varchar(1) NULL,
	REMAKE varchar(250) NULL,
	MOD_ID varchar(20) NULL,
	FYDM varchar(6) NOT NULL,
	PAGE_TYPE varchar(2) NULL,
	CONSTRAINT T_MODULE_ONLINE_PK PRIMARY KEY (LSH)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT T_MODULE_ONLINE (LSH,GNDM,GNMC,GN_URL,IMG_URL,PXH,STATE,REMAKE,MOD_ID,FYDM,PAGE_TYPE) VALUES('1','WAK01','我的案款','wak/wdakView','/icon/wdakLog.png',1,'1','进行线上支付','WAK','999999','01');

13.17.2.index.js加载功能模块

const App = getApp();
var Base64 = require('../../utils/base64Decode.js');
Page({
    /**
     * 页面的初始数据
     */
    data: {
        yhxm: '',
        dwdm: '',
        yhdm: '',
        tab: []
        //测试数据
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        var userInfo = wx.getStorageSync("userInfos");
        this.setData({
            yhxm: userInfo.xm,
            dwdm: userInfo.dwdm,
            yhdm: userInfo.yhdm,
        })
        //加载功能模块数据
        this.loadModInfo();
    },
    /**
     * 初始化时获取页面的功能模块信息
     */
    loadModInfo: function () {
        var self = this;
        var userInfo = wx.getStorageSync("userInfos");
        var param = {
            "mod_id": "WAK",
            "fydm": App.globalData.FYDM,
            "yhdm": userInfo.yhdm
        }
        console.log("初始化时获取页面的功能模块的参数是:" + param);
        App.request.loadModInfo(App.globalData.IPURL, param, function (response) {
            var result = JSON.stringify(response);
            result = JSON.parse(result);
            // console.log(result);
            if (result.code == "00") {
                //遍历首页的功能模块,为其跳转的地址根据功能代码(gndm)为其赋值参数
                //1.如果是跳转到H5页面,将地址和参数准备好后使用Base64编码后存放在url中,在container.js中获取后直接解码使用
                for (var i = 0; i < result.modlist.length; i++) {
                    var module = result.modlist[i];
                    if (module.gndm == "WAK01") {
                        module.url = Base64.encode(module.url + "?openid=" + userInfo.openid + "&yhdm=" + userInfo.yhdm);
                    } else if (module.gndm == "WAK02") {
                        module.url = Base64.encode(module.url + "?yhid=" + userInfo.yhdm + "&fydm=" + userInfo.dwdm);
                    }
                    //如果module.url为空,则为未配置页面,跳转到指定的404页面
                    if (module.url == " " || module.url == "") {
                        module.type = '01';
                        module.url = Base64.encode("wak/errorPage" + "?title=" + module.name);
                    }
                }
                self.setData({
                    tab: result.modlist
                })
            }
        })
    },

    /** 
     * 调用微信扫一扫进行识别二维码进行,并将二维码的内容传递到sendCheckMsg做处理
     */
    getScancode: function () {},
})

13.17.3.index.wxml

<view class="safk_index">
	<!-- 2.页面上部,显示上部主体图片 -->
	<view class="index_platform_img">
		<view class="index_platform_view">
			<view class="title"></view>
			<image mode="widthFix" src="/images/banner1.jpg" class="background"></image>
			<view class='imagesize'>
				<image src="/icon/wakLogo.png" style="position: fixed" class="logo"
					style="width: 200rpx;height:200rpx ;margin-top:60rpx;padding-left:275rpx;padding-right:275rpx">
				</image>
			</view>
			<view class="child">人民法院微案款平台</view>
		</view>
	</view>

	<!-- 3.显示欢迎用户信息-->
	<view class="user_welcome_wrap">
		<view>{{'欢迎您,'+yhxm}}</view>
	</view>

	<!-- 4.根据传入的数据动态显示宫格(一行两列图标)信息 -->
	<view class="weui-grids">
		<view class="weui-grid" wx:for="{{tab}}" wx:key="gndm">
			<!-- 4.1.当页面为H5页面时(对应T_MODULE_ONLINE的type字段为01),跳转到container(H5页面容器),打开H5页面 -->
			<view wx:if="{{item.type=='01'}}">
				<navigator url="/pages/container/container?pageUrl={{item.url}}">
					<view class='weui_grid_bg'>
						<!-- 4.1.1.显示功能模块log -->
						<view class="weui_grid_icon">
							<image src="{{item.icon}}" mode="scaleToFill" />
							<!-- 4.1.2.针对需要在图片右上角显示提示数字的设置,例如未审批的流程数-->
							<text class="span"
								wx:if="{{(item.mark=='true')&&(item.digital>0)&&(item.digital<=99)}}">{{item.digital}}</text>
							<text class="span" wx:elif="{{(item.mark=='true')&&(item.digital>99)}}">99+</text>
						</view>
						<!-- 4.1.3.显示功能模块名称 -->
						<text class="weui_grid_label">{{item.name}}</text>
						<!-- 4.1.4.显示功能模块说明 -->
						<text class="weui_grid_info">{{item.info}}</text>
					</view>
				</navigator>
			</view>
			<!-- 4.2.当页面为微信小程序页面时(对应T_MODULE_ONLINE的type字段为03),跳转到该微信小程序页面 -->
			<view wx:elif="{{item.type=='03'}}">
				<navigator url="{{item.url}}">
					<view class='weui_grid_bg'>
						<!-- 4.2.1.显示功能模块log -->
						<view class="weui_grid_icon">
							<image src="{{item.icon}}" mode="scaleToFill" />
						</view>
						<!-- 4.2.2.显示功能模块名称 -->
						<text class="weui_grid_label">{{item.name}}</text>
						<!-- 4.2.3.显示功能模块说明 -->
						<text class="weui_grid_info">{{item.info}}</text>
					</view>
				</navigator>
			</view>
			<!-- 4.3.当点击为打开首页的一个函数时(对应T_MODULE_ONLINE的type字段为02),点击 -->
			<view wx:else>
				<view bindtap="{{item.url}}" class='weui_grid_bg'>
					<!-- 4.3.1.显示功能模块log -->
					<view class="weui_grid_icon">
						<image src="{{item.icon}}" mode="scaleToFill" />
					</view>
					<!-- 4.3.2.显示功能模块名称 -->
					<text class="weui_grid_label">{{item.name}}</text>
					<!-- 4.3.3.显示功能模块说明 -->
					<text class="weui_grid_info">{{item.info}}</text>
				</view>
			</view>
		</view>
	</view>
</view>

13.17.4.index.wxss

.safk_index .title_index {
    height: 80rpx;
}

.safk_index .title_index .title_msg {
    display: flex;
}

.safk_index .title_index .title_msg .title_img_wrap {
    flex: 1;
    display: flex;
    justify-content: left;
    align-items: center;
}

.safk_index .title_index .title_msg .title_img_wrap image {
    margin-left: 10rpx;
    width: 65rpx;
    height: 65rpx;
}

.safk_index .title_index .title_msg .title_info_wrap {
    flex: 7;
    display: flex;
    justify-content: left;
    align-items: left;
    flex-direction: column;
    justify-content: space-around;
}

.safk_index .index_platform_img .index_platform_view {
    width: 750rpx;
    height: 340rpx;
    position: relative;
}

.safk_index .index_platform_img .index_platform_view image {
    width: 100%;
}

.safk_index .user_welcome_wrap {
    margin-top: 80rpx;
    background-color: #fff;
    padding: 20rpx;
}

.weui-grids {
    position: relative;
    overflow: hidden;
}

.weui-grids:before {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    height: 2rpx;
    border-top: 2rpx solid #d9d9d9;
    color: #d9d9d9;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scaleY(0.5);
    transform: scaleY(0.5);
}

.weui-grids:after {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 2rpx;
    bottom: 0;
    border-left: 2rpx solid #d9d9d9;
    color: #d9d9d9;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scaleX(0.5);
    transform: scaleX(0.5);
}

.weui-grid {
    position: relative;
    float: left;
    padding: 20rpx 20rpx;
    width: 50%;
    height: 200rpx;
    box-sizing: border-box;
}

.weui-grid:before {
    content: " ";
    position: absolute;
    right: 0;
    top: 0;
    width: 2rpx;
    bottom: 0;
    border-right: 2rpx solid #d9d9d9;
    color: #d9d9d9;
    -webkit-transform-origin: 100% 0;
    transform-origin: 100% 0;
    -webkit-transform: scaleX(0.5);
    transform: scaleX(0.5);
}

.weui-grid:after {
    content: " ";
    position: absolute;
    left: 0;
    bottom: 0;
    right: 0;
    height: 2rpx;
    border-bottom: 2rpx solid #d9d9d9;
    color: #d9d9d9;
    -webkit-transform-origin: 0 100%;
    transform-origin: 0 100%;
    -webkit-transform: scaleY(0.5);
    transform: scaleY(0.5);
}

.weui-grid:active {
    background-color: #ECECEC;
}

.weui_grid_bg {
    position: relative;
    float: left;
    padding: 0rpx 0rpx;
    width: 100%;
    box-sizing: border-box;
}

.weui_grid_icon {
    width: 64rpx;
    height: 64rpx;
    margin: 0 auto;
}


.weui_grid_icon image {
    display: block;
    width: 100%;
    height: 100%;
}

.weui_grid_icon+.weui_grid_label {
    margin-top: 4rpx;
}


.weui_grid_label {
    display: block;
    text-align: center;
    font-weight: bold;
    color: #000;
    font-size: 28rpx;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

.weui_grid_info {
    display: block;
    text-align: center;
    font-weight: bold;
    color: #C0C0C0;
    font-size: 24rpx;
    text-overflow: ellipsis;
    overflow: hidden;
}

.child {
    width: 750rpx;
    height: 48rpx;
    position: absolute;
    font-size: 52rpx;
    color: white;
    left: 0;
    top: 260rpx;
    right: 0;
    bottom: 0;
    margin: auto;
    text-align: center;
}

.background {
    width: 100%;
    height: 100%;
    position: fixed;
    background-size: 100% 100%;
    z-index: -1;
}

.title_name {
    width: 750rpx;
    height: 40rpx;
    position: absolute;
    font-size: 28rpx;
    color: white;
    left: 0;
    top: 40rpx;
    right: 0;
    bottom: 0;
    text-align: center;
}

.bgv {
    width: 100%;
    height: auto;
    position: absolute;
    top: 0;
    bottom: 0;
}

.weui-grid .span {
    position: absolute;
    /* 根据需要调整top和right */
    top: 0rpx;
    right: 85rpx;
    display: inline-block;
    padding: 4rpx 10rpx;
    min-width: 16rpx;
    border-radius: 36rpx;
    background-color: #fa5151;
    /* background-color: var(--weui-RED); */
    color: #fff;
    line-height: 1.2;
    text-align: center;
    font-size: 24rpx;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值