赞
踩
前言:
WXML
和 Wxss
,以及基于javascript的逻辑层框架, 并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑。优点:
微信小程序APP(ID): xxxxx
1.项目结构
|----|---index /首页 |---index.js /首页逻辑文件 |---index.json //首页配置文件 |---index.wxml /首页视图文件 |---index.Wxss //首页样式文件 |----|----1ogs“日志页面 |---logs.js |---1ogs.json |---logs.wxml |---logs.wxss |---utils /1工具文件夹 |--util.js |---app.js //全局入口文件 |---app.json //全局配置文件 |---app.NXss //全局样式文件 |---project.config.json //项目配置文件 |---sitemap.json //索引配置文件
2.app.json应用配置项
小程序根目录下的 app.json
文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。完整配置项说明请参考小程序全局配置
以下是一个包含了部分常用配置选项的 app.json
:
{ "pages": [ "pages/index/index", "pages/logs/index" ], "window": { "navigationBarTitleText": "Demo" }, "tabBar": { "list": [{ "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/logs/index", "text": "日志" }] }, "networkTimeout": { "request": 10000, "downloadFile": 10000 }, "debug": true }
其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
pagePath | string | 是 | 页面路径,必须在 pages 中先定义 |
text | string | 是 | tab 上按钮文字 |
iconPath | string | 否 | 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
selectedIconPath | string | 否 | 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
每一个小程序页面也可以使用同名 .json
文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json
的 window
中相同的配置项。完整配置项说明请参考小程序页面配置
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示", // 页面导航标题
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
"enablePullDownRefresh":true, // 上拉刷新,开启后onPullDownRefresh才有效
"backgroundTextStyle": "dark", // 上拉刷新的等待图标
"usingComponents": { // 引入组件
...
}
}
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
1.onLaunch | function | 否 | 生命周期回调——监听小程序初始化。 | ||
2.onShow | function | 否 | 生命周期回调——监听小程序启动或切前台。 | ||
3.onHide | function | 否 | 生命周期回调——监听小程序切后台。 | ||
onError | function | 否 | 错误监听函数。 | ||
onPageNotFound | function | 否 | 页面不存在监听函数。 | 1.9.90 | |
onUnhandledRejection | function | 否 | 未处理的 Promise 拒绝事件监听函数。 | 2.10.0 | |
onThemeChange | function | 否 | 监听系统主题变化 | 2.11.0 | |
其他 | any | 否 | 开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问 |
// app.js App({ /* 1.监听小程序的初始化 */ // 获取用户信息 onLaunch(){ console.log("onLaunch") }, /* 2.监听小程序启动或者切换前台 */ // 对页面的数据和效果进行重置 onShow(){ console.log("onShow") }, /* 3.监听小程序切后台 */ // 清除定时器 onHide(){ console.log("onHide") }, /* 错误监听函数 */ // 收集错误,通过异步请求发送服务器 onError(e){ console.log(e) }, /* * 页面不存在监听函数 * 启动时的入口文件不存在时才触发 * 一般多用于扫码进入页面时的处理 */ onPageNotFound(){ // 当页面不存在的时候,进行重定向,跳转到存在的页面 console.log("onPageNotFound") wx.navigateTo({ url: '/pages/page3/page3', }) } })
app.js中有一个 globalData, 可以用于放置全局变量或者常量。
在其它js文件中使用以下代码,获取数据。
const app = getApp(); const baseUrl = app.globalData.baseUrl;
- 1
- 2
注意:前台、后台定义: 当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。
属性 | 类型 | 说明 |
---|---|---|
data | Object | 页面的初始数据 |
1.onLoad(mounted) | function | 生命周期回调—监听页面加载 |
2.onReady | function | 生命周期回调—监听页面初次渲染完成 |
3.onShow | function | 生命周期回调—监听页面显示 |
4.onHide | function | 生命周期回调—监听页面隐藏 |
5.onUnload(unmounted) | function | 生命周期回调—监听页面卸载 |
6.onPullDownRefresh | function | 监听用户下拉动作 |
7.onReachBottom | function | 页面上拉触底事件的处理函数 |
8.onTabItemTap | function | 当前是 tab 页时,点击 tab 时触发 |
onShareAppMessage | function | 用户点击右上角转发 |
onShareTimeline | function | 用户点击右上角转发到朋友圈 |
onAddToFavorites | function | 用户点击右上角收藏 |
onPageScroll | function | 页面滚动触发事件的处理函数 |
onResize | function | 页面尺寸改变时触发,详见 响应显示区域变化 |
onSaveExitState | function | 页面销毁前保留状态回调 |
其他 | any | 开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问。这部分属性会在页面实例创建时进行一次深拷贝。 |
Page({ /* 页面的初始数据 */ data: { }, /* 1.生命周期函数--监听页面加载 */ // 发送异步请求,初始化页面数据 // 一个页面只会调用一次。 // 接收页面参数 可以获取wx.navigateTo和wx.redirectTo及中的 query。 onLoad: function (options) { console.log("onLoad") }, /* 2.生命周期函数--监听页面初次渲染完成 */ onReady: function () { console.log("onReady") }, /* 3.生命周期函数--监听页面显示 */ // 每次打开页面都会调用一次。**tabBar切换无效 onShow: function () { console.log("onShow") }, /* 4.生命周期函数--监听页面隐藏 */ onHide: function () { console.log("onHide") }, /* 5.生命周期函数--监听页面卸载 */ // 当redirectTo或navigateBack的时候调用。 (navigateTo无效) onUnload: function () { console.log("onUnload") }, /* 1.页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { console.log("onPullDownRefresh") }, /* 2.页面上拉触底事件的处理函数 */ // 上拉加载数据 onReachBottom: function () { console.log("onReachBottom") }, /* 3.切换tab页 */ // 当前是 tab 页时,点击 tab 时触发 onTabItemTap: function () { console.log("onReachBottom") }, })
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。其中,最重要的生命周期是 created
attached
detached
,包含一个组件实例生命流程的最主要时间点。
created
生命周期被触发。此时,组件数据 this.data
就是在 Component
构造器中定义的数据 data
。 此时还不能调用 setData
。 通常情况下,这个生命周期只应该用于给组件 this
添加一些自定义属性字段。attached
生命周期被触发。此时, this.data
已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。detached
生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached
会被触发。1.组件的生命周期
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
1.created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 |
2.attached (mounted) | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 |
3.ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 |
4.moved(update) | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 |
5.detached (unmounted) | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 |
error | Object Error | 每当组件方法抛出错误时执行 | 2.4.1 |
代码示例:
Component({ // 自小程序基础库版本 [2.2.3](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) 起,组件的的生命周期也可以在 `lifetimes` 字段内进行声明(这是推荐的方式,其优先级最高)。 lifetimes: { created: function() { // 在组件实例进入创建节点树时执行 }, attached: function() { // 在组件实例进入页面节点树时执行 }, ready: function() { // 在组件实例进入创建节点树时执行 }, moved: function() { // 在组件实例进入创建节点树时执行 }, detached: function() { // 在组件实例被从页面节点树移除时执行 }, }, })
2.组件所在页面的生命周期
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
代码示例:
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
注意: 在标签中使用变量,必需使用双括号和引号共同作用,才能进行数据的绑定。
使用方式 和vue类似,都可以在双括号内使用变量,进行数据绑定。
双括号内可以进行三元运算、和算术运算, 组成新的数据, 但唯一不允许构造成对象使用
1.数据绑定
<!-- 在标签中的属性使用变量,需要双括号和引号共同使用 -->
<view data-msg="{{msg}}">{{obj.age}}</view>
<view wx:if="{{num == 1}}">{{ [msg,num] }}</view>
2.表单数据的双向绑定
// vant组件中使用model进行绑定
<van-cell-group>
<van-field model:value="{{ value }}"
placeholder="请输入用户名" border="{{ false }}" />
</van-cell-group>
使用方法也与vue相同, 但是需要添加wx的专属属性绑定和数据绑定
<!-- 1.简写模式 --> <view wx:for="{{arr}}" wx:key="*this">{{item}}</view> <!-- 2.完整模式 --> <!-- (1.遍历数组 --> <!-- 默认列表项是item,索引是index, 可以省略 --> <view wx:for="{{persons}}" wx:for-item="item" // wx:for-item是默认的 wx:for-index="index" // wx:for-index是默认的 wx:key="id"> // wx:key 关键区分字段 <view>索引:{{index}}</view> <view>姓名:{{item.name}}</view> </view> <!-- (2.遍历对象 --> <view wx:for="{{obj}}" wx:key="*this" // *this表示当前的item数据项 wx:for-item="value" wx:for-index="key" > <view>对象的key:{{key}} </view> <view>对象的value:{{value}} </view> </view>
小程序是wx:elif,vue是v-else-if
wx:elif
和 wx:else
来添加一个 else 块:
<!-- if条件判断 -->
<view wx:if="{{num == 1}}">{{ [msg,num] }}</view>
<!-- if..elif..条件判断 -->
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<!-- wx:for列表渲染 -->
1.创建模板
模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs />
模块。
<!-- 定义模板 -->
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
<!-- 使用模板 -->
<template is="msgItem" data="{{...item}}"/>
<template is="msgItem" data="{{index:item.index, msg:item.msg, time:item.time}}"/>
2.引用模板
<!-- item.wxml --> <template name="odd"> <text> 单数</text> </template> <template name="even"> <text> 复数</text> </template> <!-- 引入模板 --> <import src="item.wxml"/> <block wx:for="{{[1,2,3,4,5]}}" wx:key="*this"> <text>{{item}}</text> <template is="{{item % 2 == 0 ? 'even' : 'odd'}}" /> </block>
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
3.使用实例
<!--pages/components/load/load.wxml--> <!-- 加载模板, 1.组件内模板,2.组件外模板, --> <!-- 作用:可以有效因页面加载缓慢,而导致的空数据 --> <template name="loadMask"> <view wx:if="{{judge}}" class="mask"></view> </template> <!-- 使用方法 --> <!-- 1.组件内模板 --> <!-- <template name="loadMask"> <view wx:if="{{judge}}" class="mask"></view> </template> --> <!-- 2.import导入模板, 引入wxss无效,需要组件内自定义 --> <!-- <import src="../components/load/load.wxml"/> <template is="loadMask" data="{{judge:!like_goods.length}}"/> --> <!--2.1 wxss 样式 .mask{ width: 100vw; height: 100vh; } -->
bindtap, bindchange, bindinput 是原生 小程序的事件绑定
bind:click , bind:change, 是vant组件常用的事件绑定方式
catchtap 禁用事件冒泡,一般设置为中间层
<-- 监听点击事件-->
<view bind:tap="onHandleClick()"> </view>
<-- 阻止冒泡事件-->
<view catchtp >
<view bind:tap="onHandleClick()"> </view>
</view>
通过api获取当前页面对象,再使用select方法查找节点
警告:微信小程序,不是非常支持修改页面。所以,不建议获取页面文档,也无法做到浏览的复杂渲染的页面。因为这种基于数据绑定的应用,本身就脱离了页面的直接控制。
(1.selectorComponent方法
vant组件中的选择节点方法。
const checkbox = this.selectComponent(`.checkboxes-${index}`);
checkbox.toggle(); // 执行实例的方法
(2.SelectorQuery方法
let query = wx.createSelectorQuery()
query.select('#payTicketBtm').boundingClientRect().exec(function(res) {
console.log("rect",res[0].height)
//res就是 所有标签为payTicketBtm的元素的信息 的数组
})
获取input输入的值
使用 bindinput 绑定输入事件, 可以通过 事件中的事件参数 e.detail.value获取输入的值
使用bindtap绑定点击事件,
点击按钮执行求和
改变data中的属性,相当于改变组件中的状态。需要使用this.setData({count:11})
处理事件的函数不能传参
要通过组件属性的形式 data- 和 e.currentTarget.dataset.name
// react中是setState, 小程序是setData, 类似react中的组件状态, this.setState
// vue,react中是target.value, 小程序是detail.value
// vue是this.xx 小程序是this.data.xx
--page4.js文件 ... /** * 页面的初始数据 */ data: { count:0, inputValue:'' }, // 处理事件函数 handleInput(e){ console.log(e, e.detail.value) this.setData({ inputValue:e.detail.value }) }, // 处理点击进行求和 handleClick(e){ this.setData({ count: this.data.inputValue + 1 }) }, // 处理事件传参 handleParams(e){ console.log("传入的参数是", e) }, ... ----page4.wxml文件 <input bindinput="handleInput" style="border:1px solid red"/> <button bindtap="handleClick">点我加一</button> <view>求和的结果是:{{count}}</view> <button bindtap="handleParams" data-name="Tome">点我传参</button>
1.基本方法catchtap
// 添加一个中间层,捕获冒泡事件
<view catchtap="handleStopPropagation">
<view bind:change="xxx">xxxx</view>
</view>
// 捕获事件冒泡,防止向父层扩散
handleStopPropagation(){
// 不执行任何数据
},
2.vant组件的 catch修饰
// vant checkbox组件的默认切换事件, 使用catch修饰tap方法
<view class=" check-item" data-check="{{item.id}}" bindtap="handleCheck" >
<van-checkbox name="{{item.id}}" class="checkboxes-{{ item.id }}" catch:tap="handleStopPropagation"/>
</view>
scroll-view组件,常用于组件中内容的滚动监听。
我们只需要将滑动报错的标签上加上一个样式即可 touch-action: none;
touch-action :当你触摸并按住触摸目标时候,禁止或显示系统默认菜单。
touch-action取值有一下两种
none:系统默认菜单被禁用
default:系统默认菜单不被禁用
添加样式更改,将滑动报错的标签样式添加: touch-action: none;
或者设置全局公共样式: *{touch-action: none;}
var hello = function(str){ return 'hello' + str; } module.exports = { hello:hello } <!-- 使用wxs --> <!-- 方法一:引入wxs文件,并重命名模块 --> <wxs src="./../comm.wxs" module="tools"/> <view>{{tools.hello("Tom")}}</view> <!--方法二:直接在当前文件定义模块 --> <wxs module="getAge"> var age = 12; module.exports = { age:age } </wxs> <view >{{getAge.age}}</view>
尺寸单位
设备 | 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 |
使用方法
使用方法和网页一样,都可以使用class
引入css模块:
@import "./../comm.wxss";
内联样式:
<!--动态样式-->
<view style="color:{{color}};" />
style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度
(1. 方法一
使用icon组件: 略
(2.方法二
使用icon标签属性,标签属性值在icon组件中查找,可以不需要添加组件
/*修改goods-icon组件中的icon标签属性*/
.van-icon.van-icon-star {
color:red;
}
vant支持原选择器的样式覆盖,但不支持更换其它选择器的样式覆盖
比如:在原选择器前添加一个(类、id选择器),则样式覆盖无效
此时可以考虑vant文档中是否有 给根节点添加类名的选项 + 把覆盖样式写在 app.css中,添加层级
--无效的样式 .page-item .van-loading__spinner.van-loading__spinner--spinner,.van-loading__dot { width: 60px!important; height: 60px!important; } --有效的样式 .van-loading__spinner.van-loading__spinner--spinner,.van-loading__dot { width: 60px!important; height: 60px!important; } <!-- 页面加载器 --> // vant组件 可以使用 添加前缀**custom-**,给根节点添加类名。 <view class="page-item"> <van-loading type="spinner" custom-class="inner-spinner"/> </view>
page, view , swiper, text 微信小程序基础组件,都是作为标签使用, vant组件, 一般不使用组件名称作为选择器使用
**常用方式:**page + xxxx选择器, 可以极大地减少!important的使用。
page .address-item{
width:100rpx!important;
}
全局样式写在app.wxss里面,所有页面共享文件里的样式
- 根节点无法与普通节点共同作用,无法找到索引。
// 选择器无效的示例,找不到子节点
.submit-item .van-button {
height:160rpx;
}
// 选择器有效示例 , 找到具体的子节点
.submit-item van-button .van-button--normal{
height:160rpx;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PV3tdTVB-1661414245340)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220212125130885.png)]
view组件, 代替div
<view hover-class="bg-red">视图容器组件</view>
**text组件,**代替span
<text user-select decode>文本组件 hello</text>
**image **图片组件
<image class="image" mode="aspectFill" src="https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg"></image>
button表单组件
<button size="mini" type="primary" loading="{{true}}">按钮</button>
<button open-type="contact">contact</button>
<button open-type="share">share</button>getUserInfo
<button open-type="getPhoneNumber" bindgetphonenumber="bindgetphonenumber">getPhoneNumber</button>
<button open-type="getUserInfo" bindgetuserinfo="bindgetuserinfo">bindgetuserinfo</button>
<button bindtap="getUserInfo" >获取用户信息</button>
<button open-type="launchApp" >launchApp</button>
<button open-type="openSetting" >打开授权页</button>
<button open-type="feedback" >打开反馈页面</button>
block组件,是一个包装元素,只接受控制属性,也不会在页面中做任何渲染。类似于template标签。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
用户名: <input placeholder="请输入用户名" bindinput="handleUsername"/> 密码: <input placeholder="请输入密码" bindinput="handlePassword"/> 性别: <radio-group bindchange="handleRadio"> <radio value="男"/>男 <radio value="女"/>女 </radio-group> 爱好: <checkbox-group bindchange="handleHobby"> <checkbox value="打篮球" checked="{{true}}"/>打篮球 <checkbox value="乒乓球"/>乒乓球 <checkbox value="羽毛球"/>羽毛球 </checkbox-group> <p> <view>用户名:{{username}}</view> <view>密码:{{password}}</view> <view>性别:{{sex}}</view> <view>爱好:{{hobby}}</view> </p> <button form-type="submit">提交 </button>
navigator组件,导航跳转
<navigator url="/pages/page3/page3" >跳转page3</navigator>
<navigator url="/pages/page3/page3" open-type="redirect">redirect 跳转page3</navigator>
<navigator url="/pages/index/index" open-type="switchTab">redirect 跳转index</navigator>
<navigator url="/pages/index/index" open-type="reLaunch">redirect 跳转index</navigator>
这个常用于当作跳转的路由方法。 也可以带参数使用。可以后退,相当于navigatorTo
<navigator url="/pages/goods/goods?id={{itemm.id}}"> </navigator>
onLoad: function (options) {
const {id} = options;
// 通过options获取跳转路由的参数
console.log("参数是",id)
},
swiper组件 ,轮播图展示
<swiper autoplay="{{true}}" indicator-dots>
<swiper-item wx:for="{{images}}" wx:key="*this" wx:for-item="url">
<image src="{{url}}"/>
</swiper-item>
</swiper>
rich-text组件,解析html
page4.js文件 html_1:'<p style="background:red">hello</p>', html_2:[ { name:"p", attrs:{ style:"color:red" }, children:[ { type:'text', text:'hello' } ] }
<!-- 5.rich-text属性渲染html -->
<rich-text nodes="{{html_1}}"></rich-text>
<rich-text nodes="{{html_2}}"></rich-text>
scroll-view组件,常用于组件中内容的滚动监听。
<scroll-view scroll-y="true" style="height: 100%" bindscrolltolower="onScrollBottom" >
</scroll-view>
web-view组件,在微信小程序中浏览网页
注意: 需要在微信开发者选项中添加允许访问的业务网站 的域名
<web-view src="https://www.xxxxxxxxx.com/index.html" />
定义一个components组件,在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。
1.component组件
-- person.js文件 Component({ /* 组件的接收属性数据 */ properties: { // 设置接收数据的类型 persons:{ type:Array, value:[] } }, /* 组件的初始数据 */ data: { title:"我是自定义组件", msg:"我是子组件中的数据", // persons:[ // {id:1,name:"Tom",age:10}, // {id:2,name:"mike",age:11}, // ] }, /* 组件的方法列表 */ methods: { handleClick(){ console.log("点击了自定义组件中的事件") }, handleMsg(){ // 派发一个自定义事件, 相当于$emit this.triggerEvent("getMsg",{msg:this.data.msg}) } }, /*监听数据的变化*/ Observe:{ showPay: function(newShowPay) { console.log("111111",newShowPay) } }, // 勾子函数,组件的生命周期 lifetimes: { created: function() { // 在组件实例进入创建节点树时执行 }, attached: function() { // 在组件实例进入页面节点树时执行 }, ready: function() { // 在组件实例进入创建节点树时执行 }, moved: function() { // 在组件实例进入创建节点树时执行 }, detached: function() { // 在组件实例被从页面节点树移除时执行 }, }, })
-- person.wxml文件
<view class="main">
<view>这里是组件的内部节点</view>
<slot></slot>
<view>{{title}}</view>
<view class="item" wx:for="{{persons}}" wx:key="id">
<view>姓名:{{item.name}}</view>
<view>年龄:{{item.age}}</view>
</view>
<button bindtap="handleClick">点击触发自定义组件中的事件</button>
<button bindtap="handleMsg">传递给父组件</button>
</view>
2.page页面
---page.json文件引入组件
{
"usingComponents": {
"Persons":"../../components/Persons/Persons"
}
}
---page.wxml文件
<view>Page5中使用自定义组件</view>
<Persons persons="{{persons}}" bindgetMsg="getMsg" >
这里的内容会显示在自定义组件中的slot占位
</Persons>
下面使用的方法与vue类似
this.triggerEvent("getMsg",{msg:this.data.msg})
派发一个自定义事件。triggerEvent很类似$emit注意:
vant组件中也可以直接使用wx:for ,等模板语法。(tab组件)。
vant组件的也有slot标签属性(goods-action组件)
<van-cell value="内容" > <view slot="title"> 把title标签属性的内容作为需要插入的数据 </view> </van-cell>
- 1
- 2
- 3
- 4
- 5
- 6
vant组件也可以不添加任何属性,直接在标签体内添加内容,即可成为插槽内容(cell单元格)
<van-cell title="设置为默认地址" > <van-switch checked="{{ checked }}" size="24px" /> </van-cell>
- 1
- 2
- 3
Component({ ... observers: { // 监听单个数据 showPay: function(newShowPay) { console.log("111111",newShowPay) } // 1. 监听多个数据 'numberA, numberB': function(numberA, numberB) { // 在 numberA 或者 numberB 被设置时,执行这个函数 this.setData({ sum: numberA + numberB }) }, // 2.监听对象的子数据 'some.subfield': function(subfield) { // 使用 setData 设置 this.data.some.subfield 时触发 // (除此以外,使用 setData 设置 this.data.some 也会触发) subfield === this.data.some.subfield }, // 3.监听列表的子数据 'arr[12]': function(arr12) { // 使用 setData 设置 this.data.arr[12] 时触发 // (除此以外,使用 setData 设置 this.data.arr 也会触发) arr12 === this.data.arr[12] }, // 4.监听所有子数据的变化, 使用双通配符 “**” 'some.field.**': function(field) { // 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发 // (除此以外,使用 setData 设置 this.data.some 也会触发) field === this.data.some.field }, } ... })
(1. 路由跳转的参数都是串行形式, navigator组件和wx.路由api的效果相同。
(2.网络请求的参数,可以为串行和请求体两种形式
(1.跳转api
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
”关闭当前页面“,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
// wx.redirectTo({
// url: '/pages/page5/page5',
// })
”关闭所有页面“,打开到应用内的某个页面, 允许跳转到tabbar页面
一般 用于扫码跳转主页面
// wx.reLaunch({
// url: '/pages/page2/page2',
// })
从tab页面,跳转其它 ”所有“ 页面
// wx.navigateTo({
// url: '/pages/page5/page5',
// })
”关闭其他所有非 tabBar 页面“, 允许跳转到 tabBar 页面
// wx.switchTab({
// url: '/pages/page2/page2',
// })
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。
// wx.navigateBack({
// delta: 0,
// })
(2.获取当前页面
getCurrentPages()
函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
let pages = getCurrentPages();
let currPage = null;
if (pages.length) {
currPage = pages[pages.length - 1];
}
console.log(currPage.route)
显示消息提示框
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000
})
// 隐藏提示框, 一般与showToast配对使用
setTimeout(()=>{
wx.hideToast( )
},1000)
显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框
wx.showLoading({
title: '加载中',
})
setTimeout(function () {
wx.hideLoading()
}, 2000)
显示模态对话框
wx.showModal({
title: '提示',
content: '这是一个模态弹窗',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
请求数据
注意:get请求的参数,可以写在data上, 可以串行和请求体的方式
vue是有data和params的区分
const requestTask= wx.request({
url: 'https://api.shop.eduwork.cn/api/index', //仅为示例,并非真实的接口地址
method:'get',
data:{
title:'java',
sort:'price'
},
success (res) {
if(res.statusCode == 200){
console.log(res.data)
}
}
})
中断请求
// requestTask.abort();
监听 HTTP Response Header 事件。会比请求完成事件更早
requestTask.onHeadersReceived(()=>{
console.log("onHeadersReceived")
})
异步存储
// 异步存储数据 wx.setStorage({ key:"key", data:"value" }) // 异步获取缓存中的数据 wx.getStorage({ key: 'key', success (res) { console.log(res.data) } }) // 异步获取当前的缓存信息 wx.getStorageInfo({ success (res) { console.log(res.keys) console.log(res.currentSize) console.log(res.limitSize) } }) // 异步移除本地缓存 wx.removeStorage({ key: 'key', success (res) { console.log(res) } }) // 异步清空本地缓存 wx.clearStorage({ success: (res) => {}, })
同步缓存
wx.setStorageSync('age', 12)
const res = wx.getStorageInfoSync( )
console.log( res.keys)
console.log( res.currentSize)
console.log( res.limitSize)
const age = wx.getStorageSync('age')
console.log(age)
wx.removeStorageSync('age')
wx.clearStorageSync()
区别:
- 调用异步api之后。不会等待执行结果,程序继续向下运行
- 调用同步api, 需要等待执行结果,程序暂停运行。
注意:
wx.login
调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成
wx.getUserProfile(Object object)
获取用户信息。页面产生点击事件(例如 button
上 bindtap
的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo
。该接口用于替换 wx.getUserInfo
wx.getClipboardData和 wx.setClipboardData
js中: // 点击复制openid textPaste(e){ wx.setClipboardData({ data: e.currentTarget.dataset.openid, success (res) { wx.getClipboardData({ success (res) { console.log(res.data) // data } }) } }) }, wxml中: <text class='shopName' bindtap='textPaste' data-openid="{{userObj.openid}}">{{userObj.openid}}</text>
wx.previewImage 图片预览
// 点击自定义预览层
handleSelfPreview(e){
const url = e.currentTarget.dataset.preview
wx.previewImage({
current:url, // 当前显示图片的http链接
urls:[url] // 需要预览的图片http链接列表
})
},
wx.startPullDownRefresh 和 wx.stopPullDownRefresh 上拉刷新
console.log("下拉刷新")
wx.startPullDownRefresh({
success:function(){
console.log("刷新成功")
}
})
wx.stopPullDownRefresh({
success:function(){
console.log("刷新结束")
}
})
openid和unionid
openid:微信用户相对于不同的公众号,不同的小程序,都有唯一的用户标识,,这个标识就是openid,在同一个公众号或者同一个小程序中,微信用户的openid是唯一的,即每个微信用户的openid是不同的
unionid;微信开放平台帐号下的唯一标识,只有公众号或者小程序绑定到微信开放平台帐号才能获取到unionid,同一个微信用户,在同一个开放平台unionid是惟一的,用做在不同的公众号或者不同的小程序中,识别同一个用户
wx.getUserProfile和wx.login
wx.getUserProfile:获取用户信息。页面产生点击事件(例如 button上 bindtap的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回userlnfo.
wx.login:调用接口获取**登录凭证(code)
。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)
**、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号〉及本次登录的会话密钥(session_key)等。
**相同点:**最终的目的都是拿到openid,用于查询数据中的用户信息
**区别:**getUserProfile需要用户操作,不可控制。
wx.login可以实现自动获取openid
总结:
1.前台发起请求:(warning)
App({ onLaunch() { // 登录 wx.login({ success (res) { if (res.code) { //发起网络请求 wx.request({ url: 'https://api.weixin.qq.com/sns/jscode2session', // 注意,不要以明文的形式, 请求用户数据。 // app.js获取不到封装页面的request文件 data: { appid:'你自己的appid', secret:'你自己的secret', js_code:res.code, grant_type:'authorization_code' } }) } else { console.log('登录失败!' + res.errMsg) } } }) }, globalData: { userInfo: null, baseUrl:'https://api.shop.eduwork.cn' } })
2.后台连接微信服务器(建议)
》》 当前小程序
》》appid , 你自己的appid
》》 secret, 你自己的secret
// app.js App({ onLaunch() { // 登录 wx.login({ success :(res)=>{ if (res.code) { //发起网络请求, wx.login获取的code, 然后通过code获取小程序的Openid和用户信息. // data里面的appid是当前的小程序的身份标识 wx.request({ url: this.globalData.baseUrl+'/api/auth/wx/code', method:'POST', data:{ appid:'你自己的appid', secret:'你自己的secret', js_code:res.code }, success(res2){ // 如果当前微信没有绑定过,只能返回openid,缓存openid,用于后续操作。 wx.setStorageSync('openid', res2.data.openid) // 如果绑定过,会返回access_token和用户信息,缓存access_token和用户信息 // 而小程序是否登录和是否有access_token是直接关系。 if(res2.data.access_token != ''){ wx.setStorageSync("access_token",res2.data.access_token) wx.setStorageSync("userinfo",res2.data.user) } } }) } else { console.log('登录失败!' + res.errMsg) } } }) }, globalData: { userInfo: null, baseUrl:'https://api.shop.eduwork.cn' } })
3.混乱secret密钥
// 检测当前的页面 export const getAlter_sec = ()=>{ return getAlter_C(getAlter_B(getAlter_A())) } // 1.混乱的短字段 export const getAlter_A = ()=>{ // 目标数据 a4f eaca b e4e4 67 f26d 8c8d a1eb22 e7 01 const _a = 'a4f a1eb22' // 1 8 const _b = 'b 67' // 3 5 const _c = 'eaca 8c8d 01' // 2 7 10 const _d = '' const _e = 'e4e4 e7' // 4 9 const _f = 'f26d' // 6 const arr = [1,8,3,5,2,7,10,0,4,9,6] const alpha = ['a','b','c','d','e','f'] let getA = Array.from('1234567890'); let _turn = -1 arr.forEach((item)=>{ if(item != 0) { _turn += 1 let t_alpha = []; alpha.forEach(subItem=>{ var t = 0; switch(subItem){ case 'a': t = _a; break; case 'b': t = _b; break; case 'c': t = _c; break; case 'd': t = _d; break; case 'e': t = _e; break; case 'f': t = _f; break; } if(t.length){ t_alpha = [...t_alpha,...t.split(' ')] } }) getA.splice(item-1,1, t_alpha[_turn]) } }) return getA } // 2.混乱的短字段2 export const getAlter_B = (newArr)=>{ // 目标数据 67 01 a4f eaca b e4e4 f26d 8c8d a1eb22 e7 // 传递的数据 a4f eaca b e4e4 67 f26d 8c8d a1eb22 e7 01 let arr = Array.from('2345067891'); let getB = Array.from('1234567890'); arr.forEach((item,index)=>{ getB.splice(item,1,newArr[index]) }) return getB } // 3.调整顺序,拼接, export const getAlter_C = (newArr)=>{ // 传入四个字符 const _a = newArr[0] const _b = newArr[1] let prefix = _a[0]+_b+_a[1] return prefix + newArr.slice(2).join(''); } export const getAlter_appid = () =>{ const _a = 'wx4cfa' const _c = 'd132eb' const _b = '9ca05f' return _a + _b + _c } module.exports = { getAlter_sec,getAlter_appid }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BittewZQ-1661414245342)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220210141956427.png)]
vant组件的upload上传(主要参考文章)
// 提交修改头像 handleConfirm(){ var tempFilePath = this.data.updateAvatarList[0].url // 监听url数据,并非data数据流 // 只有更换才会显示发起请求的数据。 if(!tempFilePath.startsWith("http://tmp/")){ wx.showToast({ title: '头像没有变化', icon:'error', duration:1500 }) return; } this.getOssKey(); }, // 1.首先通过后端api返回一个oss接口信息 getOssKey(){ ossPicKey().then(res=>{ console.log("返回的结果是",res) this.setData({ ossKey:res }) this.handleOss(); }) }, // 2.通过组件将oss转换成在线的图片链接 handleOss(){ console.log("处理在线的链接",this.data.ossKey) //上传的文件信息, 临时的url才有效,已经存在的在线链接,则无效。 var tempFileDataUrl = this.data.updateAvatarList[0].url // 监听url数据,并非data数据流 var prefixUrl = this.data.ossKey.host; // 图片链接前缀 var filename = Date.now() + 'aaa.png' // 文件名称 var filepath = `BoardShopping/${filename}` // 文件路径 (含文件名称) wx.uploadFile({ // 目标url "https://laravel-book-shop.oss-cn-beijing.aliyuncs.com/", url: prefixUrl, // 图片链接前缀 filePath: tempFileDataUrl, // 临时url文件 name: 'file', // 文件类型,(图片也可以是file类型) // 获取oss数据, 必须是后端已经注册的用户 formData: { name: tempFileDataUrl, // 临时url文件 key: filepath, // 文件路径(含文件名称) policy: this.data.ossKey.policy, // plicy政策 OSSAccessKeyId: this.data.ossKey.accessid, // osss访问id success_action_status: "200", // 成功的状态码 signature: this.data.ossKey.signature, // 签名验证 }, success: (res)=>{ const status = `${res.statusCode}` if(!status.startsWith("2")){ console.log('请求错误1: ', res) wx.showToast({ title: "上传失败", icon: 'error', duration: 1500 }) }else{ // 完成的图片连接 const newLink = prefixUrl + filepath ; console.log("获取的url链接",newLink) // 因为是回调函数, 所以并不能在回调函数中获取页面定义的方法,但箭头函数可以在上级查找data数据 this.handleAvatar(newLink); } }, fail:(err)=>{ console.log('请求失败2: ', err.errMsg) wx.showToast({ title: "上传失败", icon:'error', duration: 1500 }) }, }) }, // 3.然后将在线图片链接上传到当前帐号 handleAvatar(newLink){ // const newAvatar = 'https://cdn.jsdelivr.net/gh/JackKetty/PicGoCDN/pic/202201051114294.jpg' const newAvatar = newLink; const data = { avatar:newAvatar } updateAvatar(data).then(res=>{ wx.showToast({ title: '更换头像成功', icon:'success', duration:1500 }) this.setData({ userObj:{ ...this.data.userObj, avatar_url:newAvatar }, preAvatar:newAvatar, updateAvatarList:[ {...this.data.updateAvatarList[0],url:newAvatar} ] }) this.handleChangeAvatar() }) },
1.使用沙箱支付宝
首先需要使用个人真实支付宝帐号申请一个沙箱帐号,里面包含 商家 和 用户 测试帐号
然后下载沙箱支付宝,使用 沙箱支付宝帐号登录,支付余额可以在 注册的支付宝帐号里面配置(真实)。
2.可以查看一下沙箱支付宝处理的流程(配置沙箱环境)
选择支付宝的 研发服务选项, 配置密钥/证书(公钥)
然后配置应用网关,用于接收支付宝沙箱环境的通知
(自己的服务器)服务端配置 支付宝网关地址 、APPID、签名方式
然后配置授权回调地址
1.基础路径
app.wxss文件
@import '/miniprogram_npm/@vant/weapp/common/index.wxss';
app.json文件
url= "pages/homePage/cart/cart" // navigator跳转路径
"iconPath": "/assets/icons/home.png", // assets路径
"pagePath": "pages/homePage/cart/cart", // tabBar路径
"pages":[ // 页面路径
"pages/homePage/index/index",
]
js文件
import {deleteAddress,defaultAddress,addresslist} from '../../../service/address'
import Notify from '../../../miniprogram_npm/@vant/weapp/notify/notify';
json文件(可以在npm构建包中直接找到)
"van-empty": "@vant/weapp/empty/index"
注意:npm构建是将npm包中的组件打包成一个miniprogram_npm 的构建组件。 可以在json文件中直接被找到
2.getapp()方法
Commonjs 语法下的模块引入
将引入的路径,切换到当前路径,使用了变量的形式。
App({
require: ($uri) => require($uri),
})
const app = getApp()
const {data} = app.require('model/test.js')
Es6 语法下的模块引入 (不建议使用)
在app.js文件中声明具体模块,并结合getApp方法获取对应的属性,然后在引入的位置执行函数,获取模块对象。
App({
alias:{
'service':()=>require("service/address")
},
})
const app = getApp();
const {deleteAddress,defaultAddress,addresslist} = app.alias.service( );
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ay4NmrzP-1661414245342)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220203001649152.png)]
3.发布小程序,在微信开发者工具中点击上传,将当前开发版本上传到 微信开发者平台上。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdjOzGHQ-1661414245344)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220203002638010.png)]
注意:如果出现 小程序真机调试遇到VM13:2 Unhandled promise rejection 90001
生命周期:
组件机制:
vue组件机制,父子之间传递数据,以及使用插槽添加额外的子数据。
微信小程序只有组件和vue类似, property 属性是继承属性, data 是数据源, methods是方法集合。 使用组件的页面可以通过标签属性传递数据, 而组件可以通过 this.triggerEvent派发一个自定义事件,页面通过 onxxxx = “xxx” 接收组件传递数据。使用方法和vue的$emit类似。
同时,可以在组件内定义slot标签,作为插槽的数据。
微信小程序的pages页面也有data数据, 通常使用 this.data.xxx获取指定数据。
pages页面
vue是通过组件的拼接形成的页面。
微信小程序也可以使用组件,但每个页面都有特定的标识。并且,page页面中的js数据源,内部其实是一个类,访问属性与方法是通过this.xxx 或者 this.data.xxx获取。
并且,vue可以直接对data中的属性进行访问,而微信小程序有react中的状态机制,只有通过
this.setData({ a: xxx}) 改变数据。即使结果相同,但是实现的方式不一样。
模块语法
vue采用简洁明了的方式,将数据与标签属性值 ,文本内容绑定。 列表循环,数据绑定,事件绑定, 条件渲染。
微信小程序采用的方法很类似vue,但却不一样。
事件绑定: 按钮采用 bindtab 表示绑定点击事件, 其余的事件采用 bindxxx, 事件名称小写的习惯进行事件绑定。
列表循环, vue采用 v-for=“item in goods” :key=“item.id” 的方式; 微信小程序采用 wx:for = “{{goods}}” wx:key=“id” wx:for-item = “item” wx:for-index = “id” 的方式。
数据绑定, 微信小程序采用 数据绑定wx:xxxx = “{{ xxx}}” , 插值{{xxxx}}
有点类似vue与react的数据绑定的结合。
条件渲染: vue采用的是v-if 和v-show ,控制节点的显示;微信小程序采用wx:if , wx:elif , wx:else 和 hidden 控制节点的显示。使用方法相同。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。