微信小程序,简称小程序,英⽂名 Mini Program ,是⼀种不需要下载安装即可使⽤的应⽤,它实现了应⽤“触⼿可及”的梦想,用户扫⼀扫或搜⼀下即可打开试用。
小程序示例源码
开发微信小程序之前,必须要准备好相应的环境
微信小程序需要标注唯一的开发者信息,因此需要申请注册账号。建议使用全新的邮箱(作为登录帐号,请填写未被微信公众平台注册,未被微信开放平台注册,未被个人微信号绑定的邮箱),没有注册过其他小程序或者公众号的。
访问注册页面,耐心完成注册即可。
由于后期调⽤微信⼩程序的接⼝等功能,需要索取开发者的⼩程序中的 APPID ,所以在注册成功后, 可登录,然后获取APPID。
登录成功后可看到如下界面
然后复制你的APPID,悄悄的保存起来,不要给别⼈看到。
下载地址
微信小程序自带开发者工具,集 **开发、预览、调试、发布 **于⼀⾝的 完整环境。
但是由于编码的体验不算好,因此 建议使⽤ vs code + 微信小程序编辑工具 来实现编码
vs code 负责敲代码, 微信编辑工具 负责预览
详细的使⽤,可以查看官网
小程序框架的目标是通过尽可能简单、⾼效的方式让开发者可以在微信中开发具有原生APP体验的服务。
小程序框架提供了自己的视图层描述语言WXML 和 WXSS ,以及 JavaScript (小程序有自己的标签、样式、文件以及逻辑文件),并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑**(我们写代码的时候尽可能少关注操作页面结构,只需要关注页面本身)**。
传统web | 微信小程序 | |
---|---|---|
结构 | HTML | WXML |
样式 | CSS | WXSS |
逻辑 | JavaScript | javascript |
配置 | 无 | JSON |
通过以上对比得出,传统web是三层结构。而微信小程序是四层结构,多了⼀层配置.json。
⼀个小程序应用程序会包括最基本的两种配置⽂件。⼀种是全局的app.json和页面自己的page.json
注意: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"
}
字段的含义
pages 字段⸺用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。
window 标题⸺定义小程序所有页面的顶部背景颜色,文字颜色定义等。
具体内容可参考
其他参考位置
下方的页面的导航栏设置在app.jsp配置,主要用于导航操作。
首先准备导航栏图标样式,同一个功能图标设置两种。一是未点击状态下显示的图标,而是点击状态下显示的图标。
在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"
}
显示效果
这里的page.json其实用来表示页面目录下的page.json 这类和小程序页面相关的配置。
开发者可以独立定义每个页面的⼀些属性,如顶部颜色、是否允许下拉刷新等等。
页面的配置只能设置 app.json 中部分 window 配置项的内容,页面中配置项会覆盖 app.json 的 window 中相同的配置项数据。
属性 | 类型 | 默认值 | 描述 |
---|---|---|---|
navigationBarBackgroundColor | HexColor | #000000 | 导航栏背景颜色,如 #000000 |
navigationBarTextStyle | String | white | 导航栏标题颜色,仅⽀持 black / white |
navigationBarTitleText | String | 导航栏标题文字内容 | |
backgroundColor | HexColor | #ffffff | 窗口的背景色 |
backgroundTextStyle | String | dark | 下拉 loading 的样式,仅支持 dark / light |
enablePullDownRefresh | Boolean | false | 是否全局开启下拉刷新。 详见Page.onPullDownRefresh |
onReachBottomDistance | Number | 50 | 页面上拉触底事件触发时距页面底部距离,单位为px。 详见Page.onReachBottom |
disableScroll | Boolean | false | 设置为 true 则页⾯整体不能上下滚动;只在页面配置中有 效,无法在app.json中设置该项 |
小程序根目录下的sitemap.json⽂件⽤于配置小程序及其页面是否允许被微信索引。
WXML(WeiXin Markup Language)是框架设计的⼀套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
小程序因为存在模板语法,所有才能实现页面渲染和动态功能。
pageName.js中Page()方法传入一个对象{……},对象有格式要求。data:{},名字是关键字,不可修改,存放初始化数据,其他的都是生命周期函数。
数据绑定的主要内容就是获取pageName.js中的data:{}中的数据,展示出来。
VS CODE可以使用微信小程序开发助手插件辅助编程
准备数据
Page({
data: {
message: 'Hello MINA!'
}
})
获取数据
<view> {{ message }} view>
准备数据
Page({
data: {
id: 0
}
})
获取数据
<view id="item-{{id}}"> view>
不要直接写 checked=false,其计算结果是⼀个字符串
<checkbox checked="{{false}}"> checkbox>
准备数据
Page({
/**
* 页面的初始数据
*/
data: {
msg: "hello mina",
num: 10000,
isGirl: false,
person: {
age: 74,
height: 145,
weight: 200,
name: "牛"
},
isChecked:true
},
})
测试
<view> {{msg}} view>
<view>{{num}}view>
<view> 是否是女生: {{isGirl}} view>
<view>{{person.age}}view>
<view>{{person.height}}view>
<view>{{person.weight}}view>
<view>{{person.name}}view>
<view data-num="{{num}}"> 自定义属性view>
<view>
<checkbox checked="{{isChecked}}"> checkbox>
view>
效果
Page({
data: {
userInfo:{},
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//页面加载是接受数据,设置参数
this.setData({
userInfo: {
xm: options.xm,
sfzh: options.sfzh,
openid:options.opendid
},
})
},
})
表达式运算是指可以在花括号中加入表达式进行简单运算
概念区分:
<view hidden="{{flag ? true : false}}"> Hidden view>
Page({
data: {
a: 1,
b: 2,
c: 3
}
})
<view> {{a + b}} + {{c}} + d view>
最终显示结果:3 + 3 + d
Page({
data: {
length:6
}
})
<view wx:if="{{length > 5}}">大于5view>
最终结果:大于5
Page({
data:{
name: 'Stonebridge'
}
})
<view>{{"hello," + name}}view>
最终显示结果:hello,Stonebridge
花括号和引号之间如果有空格,将最终被解析成为字符串
<view>{{1+1}}view>
<view>{{'1'+'1'}}view>
<view>{{ 11%2===0 ? '偶数' : '奇数' }}view>
最终效果:
wx:for="{{数组或者对象}}" wx:for-item=“循环项的名称” wx:for-index=“循环项的索引”
wx:key=“唯一的值” 用来提高列表渲染的性能
wx:key 绑定一个普通的字符串的时候那么这个字符串名称肯定是循环数组中的对象的唯一属性。
wx:key ="*this" 就表示你的数组是一个普通的数组 *this 表示是循环项
[1,2,3,44,5]
[“1”,“222”,“adfdf”]
当出现数组的嵌套循环的时候,尤其要注意以下绑定的名称不要重名
wx:for-item=“item” wx:for-index="index"
默认情况下我们不写wx:for-item=“item” wx:for-index=“index”。小程序也会把循环项的名称和索引的名称item和index。故只有一层循环的话 (wx:for-item=“item” wx:for-index=“index”)可以省略。
示例
准备数据
Page({
/**
* 页面的初始数据
*/
data: {
list:[
{
id:0,
name:"尤里"
},
{
id:1,
name:"普莱斯"
},
{
id:2,
name:"麦克塔维什"
}
]
},
})
显示数据
<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”**可省略
最终效果
示例
准备数据
Page({
/**
* 页面的初始数据
*/
person: {
age: 74,
height: 145,
weight: 200,
name: "麦克塔维什"
}
},
})
展示数据
<view>
<view>对象循环view>
<view wx:for="{{person}}" wx:for-item="value" wx:for-index="key" wx:key="age">属性:{{key}}--值:{{value}}view>
view>
最终效果
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);
}
}
示例
展示数据
<view>
<block wx:for="{{list}}" wx:for-item="item" wx:for-index="index" wx:key="id" class="my_list">
索引:{{index}}
--
值:{{item.name}}
block>
view>
最终效果
在框架中,使⽤ 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}}">1view>
<view wx:elif="{{flase}}">2view>
<view wx:else> 3 view>
view>
示例:
示例
<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一起使用
**当标签频繁的切换显示的时候 优先使用 hidden通过添加样式的方式来切换显示 **
小程序中绑定事件,通过bind关键字来实现。如bindtap、bindinput、bindchange等不同的组件支持不同的事件,具体看组件的说明即可。
<input bindinput="handleInput" />
Page({
// 绑定的事件
handleInput: function(e) {
console.log(e);
console.log("值被改变了");
}
})
绑定事件时不能带参数不能带括号,以下为错误写法
<input bindinput="handleInput(100)" />
事件传值通过标签自定义属性的方式 和 value
<input bindinput="handleInput" data-item="100" />
事件触发时获取数据
handleInput: function(e) {
// {item:100}
console.log(e.currentTarget.dataset)
// 输入框的值
console.log(e.detail.value);
}
需求:
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>
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当中
不能直接
this.data.num=e.detail.value
this.num=e.detail.value
正确的写法
this.setData({
num:e.detail.value
})
需要加入一个点击事件
WXSS( WeiXin Style Sheets )是⼀套样式语言,⽤于描述 WXML 的组件样式。
与 CSS 相比,WXSS 扩展的特性有:
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/屏幕宽度) |
---|---|---|
iPhone5 | 1rpx = 0.42px | 1px = 2.34rpx |
iPhone6 | 1rpx = 0.5px | 1px = 2rpx |
iPhone6 Plus | 1rpx = 0.552px | 1px = 1.81rpx |
建议: 开发微信小程序时设计师可以⽤ iPhone6 作为视觉稿的标准。
使用步骤:
wxml
<view>RPXview>
wxss
view{
width:200px;
height:200px;
font-size:40px;
background-color:aqua;
}
效果
使用像素定义元素长度不管使用什么设备,元素长度不变。
iPhone6屏幕
iPad屏幕
wxss
view{
width:200rpx;
height:200rpx;
font-size:40rpx;
background-color:aqua;
}
效果
使用rpx定义元素长度,元素长度自适应屏幕比例为该长度在750rpx的长度比例
小程序中不需要主动来引入样式文件,页面的会自动引入其样式文件PageName.wxss
需要把页面中某些元素的单位由px改成 rpx
设计稿 750x
750 px = 750 rpx
1 px = 1 rpx
把屏幕宽度 改成 375px
375 px = 750 rpx
1 px = 2rpx
1rpx = 0.5px
存在一个设计稿宽度100像素(px)在未知页面page像素
设计稿 page存在一个元素宽度100px
拿以上的需求 去实现 不同宽度的页面适配
page px = 750 rpx
1px = 750 rpx / page
100 px = 750 rpx * 100 / page
利用一个属性calc属性 css 和 wxss 都支持一个属性
width:calc(750rpx * 100 / 375);,375为屏幕像素
示例:
view{
/* width: 200rpx; */
height: 200rpx;
font-size: 40rpx;
background-color: aqua;
/* 以下代码写法是错误 */
/* width:750 rpx * 100 / 375 ; */
width:calc(750rpx * 100 / 375);
}
效果
wxss中直接就⽀持,样式导⼊功能。
也可以和 less中的导⼊混⽤。
使用@import 语句可以导⼊外联样式表,只⽀持相对路径。
创建style/common.wxss
view{
color: aqua;
font-size: 100px;
}
在页面的wxss中引入
/*
1 引入的 代码 是通过 @import 来引入
2 路径 只能写相对路径
*/
@import "../../styles/common.wxss";
特别需要注意的是小程序不支持通配符 * 因此以下代码无效!
*{
margin:0;
padding:0;
box-sizing:border-box;
}
解决方案:view,text,img{……}
目前支持的选择器有:
选择器 | 样例 | 样例描述 |
---|---|---|
.class | .intro | 选择所有拥有 class=intro 的组件 |
#id | #firstname | 选择拥有 id=firstname 的组件 |
element | view | 选择所有 view 组件 |
element, element | view, checkbox | 选择所有⽂档的 view 组件和所有的 checkbox 组 件 |
nth-child(n) | view:nth-child(n) | 选择某个索引的标签 |
::after | view::after | 在 view 组件后边插⼊内容 |
::before | view::before | 在 view 组件前边插⼊内容 |
原⽣⼩程序不⽀持 less ,其他基于⼩程序的框架⼤体都⽀持,如 wepy , mpvue , taro 等。 但是仅仅因为⼀个less功能,⽽去引⼊⼀个框架,肯定是不可取的。因此可以⽤以下⽅式来实现
编辑器是 vscode
安装插件 easy less
在vs code的设置中settings.json加入如下
"less.compile": {
"outExt":".wxss"
}
在要编写样式的地⽅,新建 less ⽂件,如 index.less ,然后正常编辑即可。
重点讲解小程序中常⽤的布局组件 view,text,rich–text,button,image,navigator,icon,swiper,radio,checkbox。 等
代替原来的 div 标签
<view hover-class="h-class">
点击我试试
view>
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
selectable | Boolean | false | ⽂本是否可选 |
decode | Boolean | false | 是否解码 |
示例:
不使用decode属性
<text selectable>
text 123 <
text>
效果
使用decode属性
<text selectable decode>
text 123 <
text>
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
src | String | 图⽚资源地址 | |
mode | String | scaleToFill | 图⽚裁剪、缩放的模式 |
lazy-load | Boolean | false | 图⽚懒加载 |
mode 有效值:
mode 有 13 种模式,其中 4 种是缩放模式,9.种是裁剪模式。
模式 | 值 | 说明 |
---|---|---|
缩放 | scaleToFill | 不保持纵横比缩放图片,使图片的宽⾼完全拉伸⾄填满image 元素 |
缩放 | aspectFit | 保持纵横比缩放图片,使图片的长边能完全显⽰出来。 |
缩放 | aspectFill | 保持纵横比缩放图片,只保证图片的短边能完全显⽰出来。 |
缩放 | widthFix | 宽度不变,⾼度⾃动变化,保持原图宽⾼⽐不变 |
裁剪 | top | 不缩放图片,只显示图片的顶部区域 |
裁剪 | bottom | 不缩放图片,只显示图片的底部区域 |
裁剪 | center | 不缩放图片,只显示图片的中间区域 |
裁剪 | left | 不缩放图片,只显示图片的左边区域 |
裁剪 | right | 不缩放图片,只显示图片的右边区域 |
裁剪 | top left | 不缩放图片,只显示图片的左上边区域 |
裁剪 | top right | 不缩放图片,只显示图片的右上边区域 |
裁剪 | bottom left | 不缩放图片,只显示图片的左下边区域 |
裁剪 | bottom right | 不缩放图片,只显示图片的右下边区域 |
示例:
WXML
<image mode="widthFix" lazy-load src="https://tva2.sinaimg.cn/large/007DFXDhgy1g51jlzfb4lj305k02s0sp.jpg" />
WXSS
image{
box-sizing: border-box;
border: 1px solid red;
width: 300px;
height: 200px;
}
效果
宽度不变,高度自动变化,保持原图宽高比不变
微信内置轮播图组件
轮播图的默认宽度 100% 高度 150px
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
indicator-dots | Boolean | false | 是否显⽰⾯板指⽰点(小圆点) |
indicator-color | Color | rgba(0, 0, 0, .3) | 指⽰点(小圆点)颜⾊ |
indicator-active-color | Color | #000000 | 当前选中的指⽰点(小圆点)颜⾊ |
autoplay | Boolean | false | 是否⾃动切换 |
interval | Number | 5000 | ⾃动切换时间间隔 |
circular | Boolean | false | 是否循环轮播 |
滑块视图容器。
滑块
滑块 默认宽度和⾼度都是100%
WXML
<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>
WXSS
/* pages/demo10/demo10.wxss */
swiper {
width: 100%;
/* height: calc(100vw * 352 / 1125); */
height: 31.28vw;/*calc(100vw * 352 / 1125)的结果*/
}
image {
width: 100%;
}
效果
导航组件 类似超链接标签
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
target | String | self | 在哪个目标上发⽣跳转,默认当前小程序,可选值 self/miniProgram |
url | String | 当前小程序内的跳转链接 | |
opentype | String | navigate | 跳转方式 |
open-type 有效值:
值 | 说明 |
---|---|
navigate | 保留当前页面,跳转到应⽤内的某个页面,但是不能跳到tabbar 页面 |
redirect | 关闭当前页面,跳转到应⽤内的某个页面,但是不允许跳转到tabbar 页面。 |
switchTab | 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 |
reLaunch | 关闭所有页面,打开到应⽤内的某个页面 |
navigateBack | 关闭当前页面,返回上一页⾯或多级页面。可通过 getCurrentPages() 获取当 前的页⾯栈,决定需要返回几层 |
exit | 退出小程序,target=miniProgram时⽣效 |
示例
WXML
<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>
效果
富文本标签
可以将字符串解析成 对应标签,类似 vue中 v–html 功能
nodes 属性⽀持 字符串 和 标签节点数组
属性 | 说明 | 类型 | 必填 | 备注 |
---|---|---|---|---|
name | 标签名 | string | 是 | ⽀持部分受信任的 HTML 节点 |
attrs | 属性 | object | 否 | ⽀持部分受信任的属性,遵循 Pascal 命名法 |
children | ⼦节点列表 | array | 否 | 结构和 nodes ⼀致 |
⽂本节点:type = text
属性 | 说明 | 类型 | 必填 | 备注 |
---|---|---|---|---|
text | ⽂本 | string | 是 | ⽀持entities |
示例1:
js(拷贝淘宝主页div串)
// pages/demo12/demo12.js
Page({
/**
* 页面的初始数据
*/
data: {
html:'……
wxml
<rich-text nodes="{{html}}">rich-text>
示例2:
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"
}
]
}
]
}
]
}
})
WXML
同示例1
效果
<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>
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
size | string | default | 否 | 按钮的大小 |
type | string | default | 否 | 按钮的样式类型 |
plain | boolean | false | 否 | 按钮是否镂空,背景⾊透明 |
disabled | boolean | false | 否 | 是否禁⽤ |
loading | boolean | false | 否 | 名称前是否带 loading 图标 |
form-type | string | 否 | ⽤于 组件,点击分别会触发 组件的 submit/reset 事件 | |
form-type | string | 否 | 微信开放能⼒ |
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的实现流程
<button open-type="contact">contactbutton>
<button open-type="share">sharebutton>
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">getPhoneNumberbutton>
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">getUserInfobutton>
<button open-type="launchApp">launchAppbutton>
<button open-type="openSetting">openSettingbutton>
<button open-type="feedback">feedbackbutton>
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
type | string | 是 | icon的类型,有效值:success, success_no_circle, info, warn, waiting, cancel, download, search, clear | |
size | number/string | 23 | 否 | icon的⼤⼩ |
color | string | 否 | icon的颜⾊,同css的color |
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>
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'
],
}
})
可以通过 color属性来修改颜色
需要搭配radio-group⼀起使用
WXML
<radio-group bindchange="handleChange">
<radio color="red" value="male">男radio>
<radio color="red" value="female" >女radio>
radio-group>
<view>您选中的是:{{gender}}view>
javascript
// pages/demo15/demo15.js
Page({
data: {
gender: ""
},
handleChange(e){
// 1 获取单选框中的值
let gender=e.detail.value;
// 2 把值 赋值给 data中的数据
this.setData({
// gender:gender
gender
})
}
})
效果
可以通过 color属性来修改颜色
需要搭配radio-group⼀起使用
类似vue或者react中的自定义组件
小程序允许我们使用自定义组件的方式来构建页面。
类似于页面,一个自定义组件由 json、wxml、wxss、js 4个文件组成
可以在微信开发者工具中的根目录下快速创建组件的文件结构components文件夹-》创建一个和自定义组件名相同的文件夹componentsName,在该文件夹上点击右键<新建Component>并输入componentsName就创建好相应的组件的需要的文件
在⽂件夹内 components/Tabs ,创建组件 名为Tabs
⾸先需要在组件的 json 文件中进行自定义组件声明
Tabs.json
{
"component": true,
"usingComponents": {}
}
同时,还要在组件的 wxml 文件中编写组件模板,在 wxss 文件中加入组件样式 slot 表⽰插槽,类似vue中的slot
Tabs.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(){}
}
})
首先要在页面的 json 文件中进行引用声明。还要提供对应的组件名和组件路径。
index.json
{
"usingComponents": {
"Tabs":"../../components/Tabs/Tabs"
}
}
index.wxml
<Tabs>Tabs>
效果:
Component 构造器可用于定义组件,调⽤ Component 构造器时可以指定组件的属性、数据、方法等。
定义段 | 类型 | 是否必填 | 描述 |
---|---|---|---|
properties | Object Map | 否 | 组件的对外属性,是属性名到属性设置的映射表,参⻅下⽂ |
data | Object | 否 | 组件的内部数据,和 properties ⼀同⽤于组件的模板渲 染 |
observers | Object | 否 | 组件数据字段监听器,⽤于监听 properties 和 data 的变 化,参见数据监听器 |
methods | Object | 否 | 组件的方法,包括事件响应函数和任意的⾃定义⽅法,关于 事件响应函数的使用,参见组件事件 |
created | Function | 否 | 组件⽣命周期函数,在组件实例刚刚被创建时执行,注意此 时不能调⽤ setData ,参见组件生命周期 |
attached | Function | 否 | 组件⽣命周期函数,在组件实例进⼊页面节点树时执行,参见组件生命周期 |
ready | Function | 否 | 组件⽣命周期函数,在组件布局完成后执行,参见组件⽣命周期 |
moved | Function | 否 | 组件生命周期函数,在组件实例被移动到节点树另⼀个位置 时执行,参见组件生命周期 |
detached | Function | 否 | 组件生命周期函数,在组件实例被从页面节点树移除时执 行,参见组件生命周期 |
父组件代码
子组件代码
11.7.示例
要求
自定义组件components(子组件)
组件Tab的tab.wxml
<view class="tabs">
<view class="tabs_title">
<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>
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": {}
}
在页面(父组件)中使用组件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
<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>3block>
Tabs>
分为应用生命周期和页面生命周期
关于小程序前后台的定义和小程序的运行机制,请参考运行机制章节。
应用指小程序的入口文件,也就是app.js
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
onLaunch | function | 否 | 监听小程序初始化,应用第一次启动就会触发的事件(例如在应用第一次启动的时候,获取用户的个人信息)。 |
onShow | function | 否 | 监听小程序启动或切前台,应用被用户看到时候触发(例如应用切换启动时,页面效果重置)。 |
onHide | function | 否 | 监听小程序切后台,应用被隐藏的时候触发(暂停或者清除定时器触发)。 |
onError | function | 否 | 错误监听函数,当应用代码发生错误的时候会触发,会有一个err的错误信息参数(在应用发生代码错误触发,可以通过异步请求将错误信息发送给后台)。 |
onPageNotFound | function | 否 | 页面不存在监听函数,页面找不到的时候报错,相当于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");
}
})
属性 | 类型 | 说明 |
---|---|---|
data | Object | 页面的初始数据 |
onLoad | function | 页面加载完毕触发,一般在这个函数发送一些异步请求来初始化页面数据 |
onShow | function | 页面显示时触发 |
onReady | function | 页面初次渲染完毕后触发 |
onHide | function | 页面隐藏的时候触发,应用隐藏以及跳转到其他页面时触发 |
onUnload | function | 页面卸载的时候触发,即关闭当前页面,跳转其他页面。(可参考10.5navigator中opne-type为关闭的时候) |
onPullDownRefresh | function | 监听用户下拉动作触发,在app.js的window中设置。可以进行页面数据属性 |
onReachBottom | function | 页面上拉触底事件的处理函数,当页面数据足够多,需要往上拉到底部的时候触发。可以用来加载下一页数据。 |
onShareAppMessage | function | 用户点击右上角转发时触发 |
onPageScroll | function | 页面滚动触发事件的处理函数 |
onResize | function | 页面尺寸改变时触发,详见响应显示区域变化,横屏,竖屏的时候发生。如果要可以发生横屏竖屏在page.json中添加"pageOrientation": “auto”,或者在app.json中设置,所有的页面都可以。 |
onTabItemTap | function | 当前是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");
}
})
当版本发布后现场进行手机端测试时,一定要将手机端的小程序删除后重新搜索添加到手机上,再进行测试
该错误一般出现在处理返回JSON数据时
RN解析数据时报错,原因是返回的数据已经是object格式
解决方案:
示例:
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
})
}
})
作用域问题——回调函数中的作用域已经脱离了调用函数了,因此需要在回调函数外边把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
})
}
})
}
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,
}
})
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,
}
引入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",
})
}
})
},
})
Page({
data: {
userInfo:{},
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//页面加载是接受数据,设置参数
this.setData({
userInfo: {
xm: options.xm,
sfzh: options.sfzh,
openid:options.opendid
},
})
},
})
直接将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
})
}
})
}
}
获取openid首先要获取通过wx.login()获取code,然后code获取appid
获取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
})
}
})
}
})
},
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);
}
通过wx.navigateToMiniProgram完成跳转
//跳转博思支付小程序完成支付
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("跳转博思支付成功");
}
})
}
}
/**
* 生命周期函数--监听页面显示
*/
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()
}
},
对于调用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
})
},
})
<web-view src="{{urlstr}}">web-view>
container.wxss和container.json不需要任何配置,省略即可
通过navigator标签携带参数跳转到container页面,携带参数通过onLoad的options接受处理
<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'>
<view class="weui_grid_icon">
<image src="{{item.icon}}" mode="scaleToFill" />
view>
<text class="weui_grid_label">{{item.name}}text>
<text class="weui_grid_info">{{item.info}}text>
view>
navigator>
view>
view>
<script type="text/javascript" th:src="@{/static/js/jweixin-1.3.2.js}"></script>
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 {
//略
}
}
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();
}
})
downloadFile.wxml
<view>view>
一般设置全局变量做到修改时全部修改,例如后台服务器地址
globalData: {
// 示例:IPURL:'http://ip:port/xszfweb/'
IPURL: 'http://192.168.1.169:8088/xszfweb/',
//订阅消息模板
SubscribeMsgTemplate:['F9eVJkbsidSFWadWAdXsj7Cjlzxg_CbtCc5e3CyOK1g']
},
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
})
}
})
}
})
wx.getAccountInfoSync().miniProgram.appId
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
<view>
<view class="btn" bindtap="load">下载view>
<loading hidden="{{ loadingHidden }}">加载中...loading>
view>
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('打开文档成功')
}
})
}
})
}
})
在图标上醒目的数字提示,告知用户有待办事项
<view class="weui-grid" wx:for="{{tab}}" wx:key="gndm">
<view wx:if="{{item.type=='01'}}">
<navigator url="/pages/container/container?pageUrl={{item.url}}">
<view class='weui_grid_bg'>
<view class="weui_grid_icon">
<image src="{{item.icon}}" mode="scaleToFill" />
<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>
<text class="weui_grid_label">{{item.name}}text>
<text class="weui_grid_info">{{item.info}}text>
view>
navigator>
view>
view>
保证item中包含digital参数,大于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;
}
引入对应的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>
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"/>
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存储参数
一般首页中需要展示为九宫格,或者六宫格展示所有的功能信息。点击功能一般为跳转到H5页面,打开小程序的另一个页面,或者调用小程序的函数等。故需要对不同情况进行不同的配置。
建表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');
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 () {
略
},
})
<view class="safk_index">
<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>
<view class="user_welcome_wrap">
<view>{{'欢迎您,'+yhxm}}view>
view>
<view class="weui-grids">
<view class="weui-grid" wx:for="{{tab}}" wx:key="gndm">
<view wx:if="{{item.type=='01'}}">
<navigator url="/pages/container/container?pageUrl={{item.url}}">
<view class='weui_grid_bg'>
<view class="weui_grid_icon">
<image src="{{item.icon}}" mode="scaleToFill" />
<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>
<text class="weui_grid_label">{{item.name}}text>
<text class="weui_grid_info">{{item.info}}text>
view>
navigator>
view>
<view wx:elif="{{item.type=='03'}}">
<navigator url="{{item.url}}">
<view class='weui_grid_bg'>
<view class="weui_grid_icon">
<image src="{{item.icon}}" mode="scaleToFill" />
view>
<text class="weui_grid_label">{{item.name}}text>
<text class="weui_grid_info">{{item.info}}text>
view>
navigator>
view>
<view wx:else>
<view bindtap="{{item.url}}" class='weui_grid_bg'>
<view class="weui_grid_icon">
<image src="{{item.icon}}" mode="scaleToFill" />
view>
<text class="weui_grid_label">{{item.name}}text>
<text class="weui_grid_info">{{item.info}}text>
view>
view>
view>
view>
view>
.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;
}