小程序
一、目录结构
pages
index
...
utils
utile.js
app.json
{
"pages":[
"pages/index/index",
"pages/favor/favor",
"pages/order/order"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#ff8189",
"navigationBarTitleText": "Weixin",
"navigationBarTextStyle":"black"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
app.js
app.wxss
三个配置json文件
二、案例
1. 数据绑定
对于页面来说, wxml文件写文本, wxss文件写样式, 如果需要绑定数据, 在js文件中的page的data中写数据, 在wxml用{{}}语法绑定, view块级元素、text行内级元素
2. 列表数据
在js的page的data中写一个数组: movies: ["少年派", "大话西游", "星际穿越", "独行月球"]
在wxml文件中展示:
<view class="movies">
<block wx:for="{{movies}}" wx:key="*this">
<view>
{{ item }}-{{ index }}
</view>
</block>
</view>
3.计数器
wxml:
<view class="counter">
<view class="count">当前计数: {{ counter }}</view>
<button bindtap="increment">+1</button>
<button bindtap="decrement">-1</button>
</view>
js:
Page({
data: {
counter: 0
},
increment() {
this.setData({
counter: this.data.counter + 1
})
},
decrement() {
this.setData({
counter: this.data.counter - 1
})
}
})
三、小程序的双线程
小程序分为视图层和逻辑层,视图层的相关任务全都在WebView里执行。
一个小程序存在多个界面,所以视图层存在多个WebView线程。
而逻辑层采用JsCore线程运行JS脚本。
他们之间通过系统层的WeixinJsBridge进行通信,也就是逻辑层把数据变化通知到视图层,触发视图层页面更新,视图层把触发的事件通知到逻辑层进行业务处理。
小程序的渲染层和逻辑层分别由2个线程管理:
-
渲染层: 界面渲染相关的任务全都在WebView里执行。一个小程序存在多个界面,所以渲染层存在多个WebView线程。
-
逻辑层:采用JsCore线程运行JS脚本。 视图层和逻辑层通过系统层的WeixinJsBridge进行通信:逻辑层把数据变化通知到视图层,触发视图层页面更新,视图层把触发的事件通知到逻辑层进行业务处理。
页面渲染的具体流程是:
在渲染层,宿主环境会把WXML转化成对应的JS对象,在逻辑层发生数据变更的时候,我们需要通过宿主环境提供的setData方法把数据从逻辑层传递到渲染层,再经过对比前后差异,把差异应用在原来的DOM树上,渲染出正确的UI界面。
四、全局APP配置文件
在pages中的页面的json文件, "enablePullDownRefresh": true 下拉刷新
tabBar配置:
"tabBar": {
"selectedColor": "#ff8189"
"list": [
{
"text": "首页",
"pagePath": "pages/index/index",
"iconPath": "assets/tabbar/home.png",
"selectedIconPath": "assets/tabbar/home_active.png"
},
...
]
}
页面page的配置:
{
"usingComponents": {},
"navigationBarTitleText": "我的首页",
"navnavigationBarBackgroundColor": "#f00",
"enablePullDownRefresh": true,
"onReachBottomDistance": 100
}
监听下拉刷新、上拉上拉加载:
Page({
data: {
avatarURL: "",
listCount: 30
},
onPullDownRefresh() {
setTimeout(() => {
this.setData({ listCount: 30 })
wx.stopPullDownRefresh({
success: (res) => {
console.log("成功停止了下拉刷新", res)
},
fail: (err) => {
console.log("失败停止了下拉刷新", err)
}
})
},1000)
},
onReachBottom() {
this.setdata({
listCount: this.listCounter + 30
})
}
})
五、app.js文件
1. 判断小程序进入的场景
onLaunch 全局执行一次
onShow 隐藏后再打开重新执行
onHide 隐藏时执行
App({
onLaunch(options) {
},
onShow(options) {
},
onHide(options) {
}
})
3. 监听生命周期函数
App({
globalData: {
token: "",
userInfo: {
name: ""
}
},
onLaunch(options) {
const token = wx.getStorageSync("token")
const userInfo = wx.getStorageSync("userInfo")
if (!token || !userInfo) {
wx.setStorageSync("token", "mytoken")
wx.setStorageSync("userInfo", { name: "abc" })
}
this.globalData.token = token
this.globalData.userInfo = userInfo
},
onShow(options) {
},
onHide(options) {
}
})
2. App()实例只有一个, 并且是共享的
App({
globalData: {
token: "",
userInfo: {
name: "abc"
}
},
})
Page({
data: {
userInfo = {}
},
onLoad() {
const app = getApp()
const token = app.globalData.token
const userInfo = app.globalData.userInfo
this.setData({ userInfo })
}
})
//index.wxml
<view class="user">name: {{ userInfo.name }}</view>
以上数据不是响应式的, 所以共享的数据通常是一些固定的数据
六、网络请求
Page({
data: {
recommends: []
},
onLoad() {
wx.request({
url: "",
success: (res) => {
console.log(this)
console.log(res)
const recommends = res.
this.setData({ recommends })
}
})
}
})
七、常见组件
1. Text文本组件(行内)
类似span标签
常见属性:
user-select 可选属性
decode 解码属性
<text user-select>Hello World</text>
<text>{{ message }}</text>
<text decode>></text>
2. Button按钮组件(块)
常见属性:
size 大小
type 样式
plain 镂空
disabled 禁止交互
loading 加载效果
hover 按钮按上去(样式自己设置)
<button size="mini">size属性</button>
<button type="primary">type属性</button>
<button plain disabled loading>其他属性</button>
<button hover-class="active">hover效果</button>
open-type 属性: 用于获取特殊权限, 绑定特殊事件
contact 打开会话
getUserInfo 获取用户信息
getPhoneNumber 获取手机号码
<button open-type="contact">
打开会话
</button>
<button bind:tap="getUserInfo">
获取用户信息
</button>
<button open-type="getPhoneNumber" bindgetPhoneNumber="getPhoneNumber">
获取手机号码
</button>
Page({
getUserInfo(event) {
wx.getUserProfile({
desc: 'desc',
}).then(res => {
console.loh(res)
})
},
getPhoneNumber(event) {
}
})
3. View视图组件(块)
类似div标签
4. Image图片组件(块)
常见属性:
src
mode 只显示图片占默认宽高的一部分
lazy-load 懒加载
<image mode="top right">显示图片右上角</image>
<image mode="aspectFill">宽度固定 高度默认裁剪</image>
<image mode="aspectFit">适配图片宽高</image>
<image mode="widthFix">宽度固定 高度自适配</image>
选择本地图片:
<button bindtap="onChooseImage">选择图片</button>
<image src="{{chooseImageUrl}}"></image>
Page({
data: {
chooseImageUrl: ""
}
onChooseImage() {
wx.chooseMedia({
mediaType: "image"
}).then(res => {
const imagePath = res.tempFiles[0].tempFilePath
this.setData({ chooseImageUrl: imagePath })
})
}
})
5. scroll-view滚动组件
局部滚动
scroll-view要有固定高度
当内容高度大于scroll-view的高度时, 就会滚动
<scroll-view class="container" scroll-y>上下滚动</scroll-view>
<scroll-view scroll-x>左右滚动</scroll-view>
scroll-view滚动监听
bindscroll 发生了滚动
bindscrolltoupper 滚动到顶部/左边
bindscrolltolower 滚动到底部/右边
<scroll-view
class="container"
scroll-x
enable-flex
bindscrolltoupper="onScrollToUpper"
bindscrolltolower="onScrollToLower"
bindscroll="onScroll"
>
</scroll-view>
Page({
onScroll(event) {
console.log("发生了滚动", event)
},
onScrollToUpper() {
console.log("滚动到最顶部/左边")
},
onScrollToLower {
console.loh("滚动到最底部/右边")
}
})
6. 组件的共同属性
id
class
style
hidden
data- * 自定义属性
bind */catch * 组件的事件
7. input的双向绑定
<input type="text" model:value="{{message}}"/>
Page({
data: {
message: "abc"
}
})
八、wxss
1. 在app.wxss编写的样式对所有pages都生效, 相当于全局样式
2. wxss支持的选择器:
.class
#id
element
::after
::before
3. 选择器的优先级
!important
style="" 1000
#id 100
.class 10
element 1
4. wxss自适应单位-rpx
rpx: 根据屏幕宽度进行自适应, 规定屏幕宽为750rpx, 如在iphone6上, 屏幕宽度为375px, 共有750个物理像素, 则750rpx = 375px = 750物理像素
对iphone6的设计稿: 1rpx = 0.5px
对iphone5的设计稿: 1rpx = 0.42px
对iphone6 Plus的设计稿: 1rpx = 0.552px
九、wxml
1. mustache语法
2. 逻辑条件判断-指令
wx:if - wx:elif - wx:else
3. hidden属性和if的区别
写上hidden属性默认值为true 但是组件树中元素还存在 所以是隐藏
用if可以直接把元素从组件树中移除
<view hidden="{{isHidden}}">123</view>
<view wx:if="{{!isHidden}}">123</view>
isHidden: false, this.setData({ isHidden: !this.data.isHidden )}
4. 列表渲染 - wx:for
<view class="books">
<block wx:for="{{books}}" wx:key="id">
{{item.name}}-{{item.price}}
</block>
</view>
books为对象数组数据, name、price为books属性
除了遍历data中的数组, 还可以遍历数字
对象类型key绑定id, 其他绑定*this
for放在block标签上, block不是组件, 只是一个包装元素, 不会在页面中做任何渲染, 只接受控制属性
给item重命名: wx:for-item="book" , 把item改成book
5. WXS
WXS是小程序的一套脚本语言, 结合wxml, 可以构建出页面的结构
WSX不依赖于运行时的基础库版本, 可以在所有版本的小程序中运行
有两种写法:
写在<wxs>标签中
写在以.wxs结尾的文件中
<wxs module="format">
// 编写纯JS代码 不要写es6语法
function formatPrice(price) {
return "$" + price
}
// 必须导出后, 才能被其他地方调用: 必须使用CommonJS导出
module.exports = {
formatPrice: formatPrice // 不能用对象增强语法
}
</wxs>
<wxs module="format" src="/">引入dormat.wxs文件</wxs>
十、组件化开发
事件的监听
1. 常见事件
bindtouchstart 手指触摸动作开始
bindtouchmove 手指触摸后移动
bindtouchcancel 手指触摸动作被打断, 如来电提醒, 弹窗
bindtouched 手指触摸动作结束
bindtap 点击
bindlongpress 长按后离开
2. 事件对象event
当某个事件触发时, 会产生一个事件对象, 并且这个对象会被传入到回调函数中
常见属性: type、timeStamp(时间戳)、target(触发事件的元素)、currentTarget(处理事件的元素)
自定义属性data-*可以在event中获取: event.currentTarget.dataset.
组件化
1. 组件化的使用
全局组件: 最外层文件夹components
局部组件: pages文件夹里创建cpns文件夹
自定义组件的引入: 在要引入组件的json文件配置 "usingComponents": {"my-cpn": "路径"} 然后可以使用组件 <my-cpn/>
自定义组件也是由4个文件组成, 常见的一个组件命名 my-cpn
2. 步骤:
在json文件中进行自定义组件声明(将component字段设为true 可这一组文件设为自定义组件)
在wxml中编写组件的模板, wxss中编写样式
在js文件中, 可以定义数据或组件内部的相关逻辑
3. 组件的通信
页面可以向组件传递内容: 数据(properties) 样式(externalClasses) 标签(slot)
Component({
properties: {
title: {
type: String,
value: "默认标题"
},
content: {
type: String,
value: "默认内容"
}
},
externalClass: ["info"],
methods: {
}
})
//使用组件的wxml
<my-cpn title="abc" content="cba"></my-cpn>
//组件的wxml文件
<view>
<view></view>
</view>
4. 插槽
在components中创建插槽文件夹my-slot, 在该文件夹的wxml文件中预留插槽<slot></slot>, view标签给my-slot的class, 在index中构建<my-slot>编写插槽的内容</my-slot>即可显示以上的view, 并且可以向插槽中编写内容
小程序的slot不支持默认值(技术难点): 创建view使用:empty伪类+兄弟选择器使插槽有插入则隐藏view
十一、API
1. 网络请求: wx.request(Object object)
url
data: 请求参数
method: 请求的方式
success: 成功时的回调
fail: 失败时的回调
Page({
onLoad() {
wx.request({
url: "",
success: (res) => {
},
fail: (err) => {
}
})
}
})
2. 设备信息和位置信息: wx.getSystemInfo(Object object)
需要在app.json中授权
"permission": {
"scope.userLocation": {
"desc": "获取你的位置信息"
}
}
3. 本地存储storage
4. 跳转和页面返回