前情:一般微信小程序大小不能超过2mib(兆),图片文件一般都是引入在线图片的形式。
一、基本语法
尽量参考官网组件的样式
1. 列表渲染和条件渲染
<!-- 1. {{}} 和vue一样,可以写单行js表达式,直接使用js文件里面data函数中的数据 -->
<view>
<text>name:{{name}} -- age:{{age}}</text>
</view>
<!-- 2. 列表渲染。微信小程序指令是wx开头wx:for 遍历数组或者对象,重复生成对应的组件。和vue的v-for用法相同。默认索引是index,默认变量的元素是item。需要指定唯一key值,提高diff算法对比效率 -->
<view wx:for="{{user}}" wx:key="index">
<text>{{index}}-name: {{item.name}}--age: {{item.age}}</text>
<view>是否成年:{{item.age>=18?'Yes':'No'}}</view>
</view>
<!-- 3. 修改默认的index索引值和 item元素变量名称 -->
<view wx:for="{{user}}" wx:for-index="i" wx:for-item="o" wx:key="name">
<view>{{i}} - 姓名:{{o.name}}</view>
<view>年龄:{{o.age}}</view>
</view>
<!-- 4. wx:if 条件渲染 -->
<view wx:if="{{age>=18}}">成年人</view>
<view wx:elif="{{age>12}}">青少年</view>
<view wx:else>未成年</view>
<!-- 6. include 引入外部的wxml文件 -->
<include scr="/home/home.wxml"></include>
<!-- 7. 事件,点击事件是bindtap,点击组件触发点击事件,可以执行js创建的函数 -->
<view bindtap="goClick">点击事件</view>
<view>error</view>
<!-- 8. 组件跳转页面 -->
<navigator url="/pages/index/index">跳转到首页</navigator>
js
Component({
data: {
name:"anna",
age:19,
user:[
{name:'zs',age:19},
{name:'fs',age:29},
{name:'jsa',age:15},
{name:'op',age:16},
],
},
goClick(){
console.log("success!");
},
})
2. 模版 template
template定义需要name
,使用需要用 is
- 第一种
<!-- 模版: 可以把代码片段写到template组件里面,在需要的地方调用模版。
2. 创建模版需要用name取模版名称
3.模板就可以直接使用传递过来的数据
-->
<template name="demo">
<view>hello!!</view>
<view>{{user[0].name}}-{{user[0].age}}</view>
</template>
<!-- 调用模版需要使用is属性指定调用的模版 模板不调用不会显示内容
3. 模版可以用过data属性传递数据
-->
<template is="demo" data="{{user}}"/>
- 可以创建一个template文件夹专门放template文件
template.wxml
<template name="tem1">
<view class="tem">
<view class="left">left</view>
<view class="right">right</view>
</view>
</template>
index.wxml
<!-- import标签引入 <import src=""/> -->
<import src="../../template/template"/>
<template is="tem1" data=""/>
<!-- index.wxss引入template的样式 -->
@import '../../template/template.wxss';
3. 模板传递数据
index.wxml
<!-- 引入模板 -->
<import src="../../template/template"/>
<!-- 模板传递数据 -->
<view wx:for="{{info}}" wx:key="index">
<template is="tem1" data="{{...item}}"/>
</view>
template.wxml
<template name="tem1">
<view class="tem">
<!-- 模板可以直接拿到传递的数据 -->
<view class="left">{{img}}</view>
<view class="right">{{text}}</view>
</view>
</template>
4. wxss 单位rpx
wxss 样式文件,私有样式,当前页面才生效。是微信小程序的样式语言,用于描述wxml样式。
wxss 支持大部分css
样式,对css进行一些扩展
页面里面的wxss是局部样式,app.wxss文件是全局样式
微信小程序里面的样式推荐
使用rpx
为单位。不管屏幕尺寸大小,都把当前屏幕设置为750rpx
。 如果设计稿不是750px
(1px!=1rpx),需要计算出1px是多少rpx
如: 375px宽度的设计搞。
750rpx ?
375 1px 750/375=2rpx。
- @import 导入外部的wxss样式文件:
@import "../home/home.wxss"
- 支持style内联样式,建议尽量不用内联样式,影响渲染速度
<view style="color:red;">hello style</view>
二、自定义组件 components
data
对象 一般存储私有数据
,
properties
对象 一般存储外部传递过来的数据
1. 自定义组件方法
需要定义在 methods
节点中
methods: {
addNum(){
this.setData({
num:this.data.num + 10
})
this._showNum()
},
_showNum(){ // 自定义内部使用的方法 建议 _开头
wx.showToast({ // 弹框
title: 'num值为'+this.data.num,
icon:"none"
})
},
}
2. 组件样式的使用
自定义组件的样式只对当前组件有效,不会影响其他组件以及小程序的页面样式。只有class样式有隔离效果,id、属性、标签选择器都没有隔离效果,但不建议使用!
自定义组件不能使用外部样式包括全局样式,需要把样式传入到自定义组件,并通过继承实现。
components.js
Component({
// 自定义组件不能使用外部样式包括全局样式,需要把样式传入到自定义组件,并通过继承实现
// 每一个样式当做一个prop属性,组件内部才能使用
externalClasses:["bgwhite","padding20","borderb"],
data: { },
})
需要把样式传到自定义组件上
<!-- 引入组件 -->
<!-- 把全局样式作为自定义组件传 -->
<textCom bgwhite="bg-white" padding20='padding-20' borderb='border-b'/>
3.父 --> 子 (通过properties属性 / 插槽)
传递数据
父:
index.wxml
<!-- 可以用{{}}给属性 绑定变量(动态属性)-->
<user title='user components!' peo="{{user}}" />
index.js
// 路由组件Page
Page({
data: {
user:{
name:'zs',
age:28,
}
},
})
子:(components组件)
user.js
// 自定义组件Component
Component({
/* 组件的属性列表,相当于vue的props属性 */
properties: { // 两种写法
title:{
type:String, //属性类型
value:"title" // 默认值 -- 传递值会覆盖默认值
},
peo: Object, // 不需要默认值可以简化,直接写定义的类型
},
})
user.wxml
<view>
<view>姓名:{{title}}</view>
<view>姓名:{{peo.name}}</view>
<view>年龄:{{peo.age}}</view>
</view>
插槽
父:
index.wxml
<view>
<user peo="{{user}}">
<view>这是一个其他页面</view>
</user>
</view>
子:(components组件)
user.wxml
<!-- 插槽,可以显示组件包含的内容 -->
<slot></slot>
4.子 --> 父
1. 通过事件触发
步骤:
- 一、
// 1. 在父组件中定义一个触发事件 --最后可用
// 4. e.detail获取子组件传参过来的值
parEvent(e){
this.setData({
count:e.detail.count
})
},
<!-- 2. 绑定 自定义的事件 -->
<son bind:sonEvent="parEvent" count="{{count}}" />
- 二、
methods: {
addCount(){
this.setData({
count:this.data.count + 10
})
// 3. 通过this.triggerEvent()触发自定义事件,并可以传参回去
this.triggerEvent("sonEvent",{count:this.data.count})
},
}
父:
index.wxml
<!-- user组件自定义事件myEvent,通过子组件触发myEvent事件执行myEventHandle函数并且传递参数 -->
<user bind:myEvent="myEventHandle" peo="{{user}}">
<view>这是一个其他页面</view>
</user>
index.js
Page({
data: {
},
myEventHandle(e){
// e是事件对象,e.detail就是子组件触发事件的第二个参数,detail对象
console.log(e.detail); //{name: "zs", age: 19}
}
})
子:(components组件)
user.wxml
<view bind:tap="emitMyevent">给父组件传值</view>
user.js
Component({
/* 组件的属性列表,相当于vue的props属性 */
properties: {
},
methods: {
emitMyevent(){
// 触发自定义事件,第一个参数是自定义事件名称,
// 第二个参数是detail对象,也就是需要传递给事件触发函数的参数对象
// 第三个参数是时间触发选项对象,可以配置事件的冒泡,捕获等(一般默认空)
this.triggerEvent("myEvent",{name:'zs',age:19},{})
}
}
})
2. selectComponent 获取子组件的实例对象
调用this.selectComponent
获取子组件的实例对象,可以直接访问子组件的任意数据和方法,调用时传入一个选择器
<!-- 2. 给子组件提供class/id选择器 -->
<son class="customA" id="cA" bind:sonEvent="parEvent" count="{{count}}" />
<!-- 1. 定义一个触发事件 -->
<button bind:tap="getChild">获取子组件的实例</button>
// 3.
getChild(){
const child = this.selectComponent(".customA")
child.setData({ // 这里不能用this,this是当前页面的实例对象
count:child.data.count + 9 // 调用子组件的数据
})
child.addCount() // 调用子组件的方法
},
5. 监听器 observers
监听器 使用键值对
的形式 键是监听字段
对象上的某个属性,值是处理函数
注意:不支持箭头函数,会改变this指向问题
// 监听器 使用键值对的形式 键是监听字段,值是处理函数
observers:{ // 监听多个字段用 , 隔开
'n1,n2':function(newN1,newN2){
this.setData({
sum:newN1 + newN2
})
}
},
methods: {
change1(){
this.setData({
n1:this.data.n1 + Math.floor(Math.random()*10)
})
},
change2(){
this.setData({
n2:this.data.n2 + Math.floor(Math.random()*10)
})
},
}
6. 触发自定义事件 triggerEvent
第一个参数是自定义事件名称,
第二个参数是detail对象,也就是需要传递给事件触发函数的参数对象
第三个参数是时间触发选项对象,可以配置事件的冒泡,捕获等(一般默认空)
this.triggerEvent("myEvent",{name:'zs',age:19},{})
三、绑定事件与冒泡
1. bind 和 catch 点击事件
<view bindtap="fatherTap">
<!-- bind:xxx 绑定的事件会有冒泡 -->
<view bind:tap="childTap">点击冒泡事件</view>
<!-- catch:xxx 绑定的事件不会冒泡 -->
<view catch:tap="childTap">点击非冒泡事件</view>
</view>
2. 小程序的函数传参
微信的事件不能加()
传递参数, 小程序给函数传递参数只能通过自定义数据
方式传递。通过事件对象
上去拿你传递的参数。
- 事件传参:
data-参数名 = '参数值'
如果定义的参数名结构:data-user-name='zs'
⇒userName
(小驼峰)
data-userName='zs'
⇒username
(全小写) - 拿参数值:
e.target.dataset.参数名
user.wxml
<!-- 微信的事件不能加()传递参数, 传递参数需要使用自定义数据的方式传递 -->
<view bind:tap="addCount" data-num="2">点击+</view>
user.js
Component({
/*组件的属性列表*/
properties: {
},
/*组件的初始数据*/
data: {
count:1,
},
/*组件的方法列表 */
methods: {
addCount(e){
// e是获取元素组件对象,e.target获取组件的自定义数据
// console.log(e);
const num = Number(e.target.dataset.num)
this.setData({
count:this.data.count+num
})
}
}
})
3. setDate方法
setDate
函数用于将数据从逻辑层发送到视图层,同时改变对应的this.data
的值。
注意:直接修改this.data
而不调用this.setData
是无法改变页面状态的,还会造成数据不一致。
<button bind:tap="changeShow">显示/隐藏</button>
<view class="box" wx:if="{{show}}"></view>
Page({
data: {
show:true,
},
changeShow(){
this.setData({
show:!this.data.show
})
},
})
4. bindtap / bindinpunt
bindtap
点击事件的处理函数
传参需要data-*=" "
,事件对象拿参数e.target.dataset.x
<button bindtap="changeCount" data-x="{{2}}"></button>
<input bindinput="change"/>
changeCount(e){
console.log(e.target.dataset.x);
},
bindinpunt
input文本框的事件处理函数
事件对象中拿文本框的输入值e.detail.value
<!-- 文本框和data之间的数据同步 -->
<input value="{{msg}}" bindinput="changeMsg"/>
data: {
msg:'Hello,'
},
changeMsg(e){ // 同步到msg
// console.log(e.detail.value);
this.setData({
msg:e.detail.value
})
},
四、behavior
behavior.js
// 遵循common.js 的规范
// 可以理解成vue的混入mixin,主要放一些公共属性
module.exports = Behavior({
data:{
sex:"man"
},
methods:{
changeSex(){
this.setData({
sex:"woman"
})
}
},
})
哪个组件使用直接引入
user.js
// 引入文件
const behavior = require('../../com/behavior')
Component({
// 用behaviors属性引入,[]可以有多个混入文件
behaviors:[behavior],
})
user.wxml
<!-- 可使用behavior的属性 -->
<view>{{sex}}</view>
<view bindtap="changeSex">改变sex</view>
五、小程序的字体图标(不支持css)
小程序不支持css文件
,不能直接使用阿里巴巴字体图标库文件,需要自定义字体
方式创建字体图标
app.wxss
/* 把icon图标放在公共样式组件内 */
/* 可以直接在线生成链接 复制源码 */
@font-face {
font-family: "iconfont"; /* Project id 4267261 */
src: url('//at.alicdn.com/t/c/font_4267261_4nl2h5taidh.woff2?t=1701342946186') format('woff2'),
url('//at.alicdn.com/t/c/font_4267261_4nl2h5taidh.woff?t=1701342946186') format('woff'),
url('//at.alicdn.com/t/c/font_4267261_4nl2h5taidh.ttf?t=1701342946186') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-shouye:before {
content: "\e600";
}
.icon-liulan:before {
content: "\e647";
}
<!-- 使用icon字体图标 -->
<text class="iconfont icon-liulan"></text>
<text class="iconfont icon-shouye"></text>
六、小程序方法
1. getCurrentPages() 获取页面栈
getCurrentPages()
获取微信小程序页面数组。[page1,page2,page3]
最后一个数组元素是当前页面,倒数第二个是上一个页面…需要倒着取。
const pages = getCurrentPages()
//console.log(pages);
const prePage = pages[pages.length-2] // 获取当前页面的上一个页面(倒数第二个页面)
// navigateBack 关闭当前页面,返回上一页面
wx.navigateBack()
2. 声明式导航 navigator
<!-- 跳转到tabbar页面 open-type要写! -->
<navigator url="/pages/index/index" open-type="switchTab">跳转到tabbar页面</navigator>
<!-- 跳转到非tabbar页面 open-type属性可以省略 -->
<navigator url="/pages/home/home">跳转到非tabbar页面</navigator>
<!-- 后退 delta后退几页(后退1页delta可省) -->
<navigator open-type="navigateBack" delta="2">返回</navigator>
3. 编程式导航
// 1.跳转tabbar页面
wx.switchTab({
url: '/pages/index/index',
})
// 2.跳转非tabbar页面
wx.navigateTo({
url: '/pages/home/home',
})
// 3.navigateBack 关闭当前页面,返回上一页面或多级页面
wx.navigateBack({
delta: 2 //返回前几页面
})
wx.navigateBack() // 返回 1页
4. 导航传参
<!-- 导航传参 ?name=zn&age=19 -->
<navigator url="/pages/home/home?name=zn&age=19">导航传参</navigator>
可以在跳转的页面onLoad()钩子拿到传递过来的参数
/* 生命周期函数--监听页面加载 */
onLoad(options) {
console.log(options); //{name: "zn", age: "19"}
},
5. 下拉刷新 onPullDownRefresh
一般是用于重置页面样式
/* 页面相关事件处理函数--监听用户下拉动作 */
onPullDownRefresh() {
this.setData({
count:0 // count重置为0
})
// 方法重置完后,调用自动关闭下拉刷新方法
wx.stopPullDownRefresh()
},
6. 上拉加载 onReachBottom
一般用于请求多条数据时 (注意:请求数据需要使用节流阀,避免多次请求数据)
默认在距离底部50px时触发,可以在全局或者局部 json去配置距离:"onReachBottomDistance": 150
/* 页面上拉触底事件的处理函数 */
onReachBottom() {
},
节流阀的使用
Page({
data: {
msg:[], // 请求的数据
// 1.定义节流阀 false可以发送网络请求,true是阻止
isLoading:false
},
getMsg(){
this.setData({isLoading:true}) // 2.正在发送网络请求,阻止再发送
// 展示Loading效果
wx.showLoading({
title: '数据加载中...',
})
// 请求后台数据
wx.request({
url: 'url',
method:'GET',
success:(res)=>{
this.setData({msg:[...this.data.msg,...res.data]})
},
complete:()=>{
wx.hideLoading() // 数据请求成功or失败都需要关闭Loading效果
this.setData({isLoading:false}) // 3.数据请求完并可以继续数据请求
}
})
},
/* 页面上拉触底事件的处理函数 */
onReachBottom() {
if(this.data.isLoading) return // 4.判断:true表示还在数据请求中,阻止请求
this.msg() // 否则可以请求
},
})