小程序
文件结构
- APP
- app.js 创建App实例代码以及一些全局相关的内容
- app.json 全局的一些配置,比如 window/tabbar
- app.wxss 全局的一些样式配置
- Page
- page.js 创建Page 实例的代码, 以及页面相关内容
- page.json 业务单独的配置,比如页面对应的 window配置,usingComponents
- page.wxml 页面的 wxml 布局代码
- page.wxss 页面的样式配置
- Component
- component.js 创建Component实例的代码,以及组件内容
- component.json 组件内部的配置,比如当前组件使用了别的组件
- component.wxml 组件的wxml布局代码
- component.wxss 组件的样式配置
从0搭建项目
- 删除项目中原有的文件(保留progect.config.js - sitemap.json)
- 找不到app.json 所以创建一个app.json文件
- 发现不能正确的解析
- 在app.json 添加 { "pages ":[“home” ]} 的json配置
- 保存上面操作后就会看到不再报错
- 创建pages文件夹,里面创建home文件夹,将home相关的内容存放在home文件夹中
- 修改home wxml中的代码,显示 helloworld
- 修改样式,补齐 app.js 和 app.wxss
小程序初体验
- 1.数据绑定
- 2.列表渲染
- 3.事件监听
数据绑定
- 对标 vue中的数据绑定,在home.js 中的初始化数据 data中定义好数据
- 在界面通过 mastach语法 引用
列表渲染
- 对标 vue中的 v-for, 这里需要使用 wx:for="{{ students }}"
- 跟vue不同,此处绑定后的值也需要使用双大括号语法,否则会解析为字符串
- 然后通过 {{ item.name }} === {{ item.age }} 方式引用
事件监听
- 首先是使用 bindtap 去绑定轻点事件,传递一个函数,不需要双大括号语法
- 在js文件中定义这个函数,因为不同于 vue 微信小程序没有数据响应式,因此不能直接通过 this.数据 = *** 去改变页面的数据,只会更改data中数据,页面并不会同步
- 因此小程序提供了 this.setData( { } ) 方法解决
subCounter(){
this.setData({
counter: this.data.counter - 1
})
}
小程序的 MVVM
- 小程序和vue 一样 使用的是 mvvm 的 设计模式
- 编程范式也是 声明式编程,通过自身 MINA 框架 充当 viewmodel的角色使得view层和 model层建立起联系,基本和 vue 一致, 符合目前主流的MVVM开发思想
配置小程序
- 小程序的很多开发需求被规定在配置文件中
- 为什么这么做
- 这样做可以更有利于我们开发的效率
- 并且可以保证开发出来的小程序的某些风格比较一致的
- 比如导航栏 顶部 TabBar 以及页面路由等等
- 常见的配置文件有哪些呢?
- project.config.json 项目配置文件,比如项目名称,appid等
- sitemap.json 小程序搜索相关的
- app.json 全局配置
- page.json 页面 配置
app.json配置
project.config.json 中的配置
- 这里面主要是配置一些版本信息,项目名称之类
sitemap.json 中配置
- 这里主要是配置一些小程序搜索相关的
app.json 中全局配置
- 全局配置比较多,可以查看完整的官方文档
- pages
- 类型 string 必填 描述:页面路径列表
- window
- Object 描述全局的默认窗口表现
- tabBar
- Object 底部 tab栏 的表现
页面配置 pages.json
每一个小程序页面也可以使用.json 文件来对本页面的窗口表现进行配置
- 页面中配置项在当前页面会覆盖app.json 的 window中相同的配置项
小程序的双线程模型
谁是小程序的宿主环境呢? 微信客户端
- 宿主环境为了执行小程序的各种文件 wxml文件,js文件,wxss文件
- 提供小程序的双线程模型
双线程模型:
- wxml模版和wxss样式运行于渲染层,渲染层使用WebView 线程渲染(一个程序有多个页面,会使用多个WebView的线程)
- js脚本(app.js/home.js等) 运行于逻辑层,使用 JsCore运行脚本
- 这两个线程都会经由 微信客户端 Native 进行中转交互
页面渲染过程-数据发生变化
通过setData 把 msg 数据 从 “Hello World” 编程 “GoodBay
- 产生的JS对象对应的节点就会发生变化
- 此时可以对比前后两个JS对象得到变化的部分
- 然后把这个差异应用到原来的Dom树上
- 从而达到更新UI的目的 ,这就是“数据驱动的原理”
界面渲染具体流程:
- 1.在渲染层,宿主环境会把WXML转化为对应的JS对象
- 2.将JS对象再次转成真实的DOM树,交由渲染层线程渲染
- 3.数据变化时,逻辑层提供最新的变化数据,JS对象发生变化进行diff算法对比
- 4.将最新变化的内容反映到真实的DOM树中 更新UI
小程序的启动流程
- 1.下载小程序包
- 2.启动小程序
- 3.加载解析 app.json
- 4.注册 App() -----> 执行App生命周期函数
- 5.加载自定义组件代码,注册自定义组件
- 加载解析page.json
- 渲染层加载渲染 page.wxml / wxss
- 逻辑层注册Page( ) ------> 执行Page生命周期函数
注册小程序 - 参数解析
每个小程序都需要在 app.js中调用App方法注册小程序实例
- 在注册时,可以绑定对应的生命周期函数,在生命周期函数中,执行对应的代码
- onLaunch 生命周期回调 ---- 监听小程序初始化,初始化后执行
- onShow 生命周期回调----监听小程序启动或者切前台, ui显示时调用
- onHide 生命周期回调 ------ 监听小程序切后台,关闭小程序时候执行
- onError 错误监听函数,当发生错误时候执行
- onPageNotFound 页面不存监听函数
- 其他 开发者可以添加任意函数或者数据变量到Object 中 用 this可以访问
获取用户信息 - 保存全局变量(getUserInfo)
获取微信用户的基本信息的方式
- 1.wx.getUserInfo 即将废弃的接口
- 2.button组件 - 将open-type 改成 getUserInfo 并且绑定 bindgetuserinfo事件去获取
- 3.使用open-data 组件展示用户信息
// 1.使用 wx.getUserInfo
//注意:此处通过this.setData修改值才能使得ui界面通过
//使用wx.getUserInfo({}) 传入一个对象,对象中传入成功 success的回调
// 因为下面需要拿到home这个this对象,在不使用第三方变量存储,bind,aplly,call 方法的情况下,使用 es6 箭头函数,保证this指针不变
onReady: function() {
wx.getUserInfo({
success: res => {
const avatarUrl = res.userInfo.avatarUrl
const city = res.userInfo.city
const nickName = res.userInfo.nickName
// this.data.name = nickName
this.setData({
name: nickName,
imgUrl: avatarUrl
})
}
})
}
//2.使用button按钮 修改open-type = "getUserInfo" 绑定事件bindgetuserinfo
<button bindgetuserinfo="getUserInfo" size="mini" open-type="getUserInfo">获取信息</button>
getUserInfo(event){
console.log(event.detail.userInfo)
}
// 使用 open-data 展示用户信息 仅仅用于展示
<open-data type="userNickName"></open-data>
<open-data type="userAvatarUrl"></open-data>
保存全局变量
// app.js中定义全局变量 globalData:{}
globalData:{
name:"alger",
age: 999
}
// 组件里面使用 const app = getApp()方法得到这个实例,再通过 app.globalData.name 拿到全局变量
// pages/home/home.js
const app = getApp()
const name = app.globalData.name
const age = app.globalData.age
知识点开始-------------
注册App时 做什么呢?
我们来思考 : 注册App时,我们一般会做什么呢?
- 1.判断小程序的进入场景
- 2.监听生命周期函数,在生命周期执行对应的业务逻辑,比如某个生命周期函数中获取用户的信息
- 3.因为App()实例只有一个,并且是全局共享的(单例对象) 所以我们可以将一些共享数据放在这里
注册page时做什么呢?
我们来思考 : 注册一个Page页面时 ,我们一般需要做什么呢?
- 1.在生命周期函数中发送网络请求,从服务器获取数据
- 2.初始化一些数据,以方便被wxml引用展示
- 3.监听wxml中的事件,绑定对应的事件函数
- 4.其他一些监听 (比如页面滚动 、上拉刷新、下拉加载更多等)
属性 | 类型 | 说明 | ||
---|---|---|---|---|
data | Object | 页面的初始数据 | ||
onLoad | function | 生命周期回调—监听页面加载 | ||
onShow | function | 生命周期回调—监听页面显示 | ||
onReady | ||||
onHide | function | 生命周期回调—监听页面隐藏 | ||
onUnload | function | 生命周期回调—监听页面卸载 | ||
onPullDownRefresh | function | 监听用户下拉动作 | ||
onReachBottom | function | 页面上拉触底事件的处理函数 | ||
onShareAppMessage | function | 用户点击右上角转发 | ||
onPageScroll | function | 页面滚动触发事件的处理函数 | ||
onResize | function | 页面尺寸改变时触发,在手机上启用屏幕旋转支持 | ||
onTabItemTap | function | 当前是 tab 页时,点击 tab 时触发 | ||
其他 | any | 开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问 |
Git 打tag ,切换回之前tag
git add .
git commit -m 05_小程序注册和页面
git tag 05_小程序注册和页面
git log
git reset --hard 03231f6e3b66deb7
// 回到05_小程序注册和页面 tag的话
git checkout 05_小程序注册和页面
//回到主分支,离开这个tag
git checkout master
小程序中的组件
- 默认情况下text的文本长按是不能被选中的, 需要的话 就添加 selectable 属性
- space 属性 决定文本空格大小 emsp半个中文字符大小 ensp 一个中文字符大小,nbsp是默认值
- decode属性 决定是否解码文本 需要的话 就添加 decode
text
<!-- 1. 基本使用 -->
<text>HelloWorld\n</text>
<text>你好小程序\n</text>
<!-- 2.默认情况下text的文本长按是不能被选中的 -->
<!-- 将 selectable: true 即可被选中 -->
<text selectable="{{true}}">Hello CodeWang\n</text>
<!-- 3. space 决定文本空格大小 -->
<text>Hello World\n</text>
<text space="nbsp">Hello World\n</text>
<text space="emsp">Hello World\n</text>
<text space="ensp">Hello World\n</text>
<!-- 4. decode 属性:是否解码文本 -->
<text decode="{{!false}}">5 > 3</text>
button
<!-- 1.基本使用 -->
<button>按钮</button>
<!-- 2.size属性 -->
<button size="mini">按钮1</button>
<button size="mini">按钮2</button>
<button></button>
<!-- 3.type 属性 -->
<button size="mini" type="primary">按钮1</button>
<button size="mini" type="default">按钮2</button>
<button size="mini" type="warn">按钮3</button>
<button></button>
<!-- 4. plain 镂空效果 -->
<button plain size="mini">按钮一</button>
<!-- 5.disabled 不可用按钮 -->
<button disabled size="mini">按钮二</button>
<!-- 6.loading 小圆圈转 -->
<button loading="{{isLoading}}" size="mini" bindtap="getData">按钮二</button>
<!-- 7.hover-class -->
<button hover-class="pressed">按钮</button>
<!-- 8. open-type的取值 -->
<!-- 获取用户一些特殊的权限,可以绑定一些特殊的事件 -->
view组件(相当于前端的div)
view组件也是块级元素
- hover-class 点击切换class属性
- hover-start-time 点击变化开始时间
- hover-stay-time 点击变化持续时间
- hover-stop-propagation 阻止祖先元素的点击态
<!-- 1.基本使用 是个容器组件 -->
<view>
<text>Hello World</text>
<button>按钮</button>
你好小程序
</view>
<!-- 2. hover-class属性 类似button 用户按下去时候显示的样式 -->
<!-- hover-start-time点击后开始变化时间 hover-stay-time点击后变化持续时间 -->
<view hover-class="hover-box1" class="box1" > 你好 我是view组件</view>
<!-- 3. hover-stop-propagation 阻止点击冒泡-->
<view class="box2" hover-class="hover-box2">
<view hover-class="hover-box1" class="box1" hover-stop-propagation> 你好 我是view组件</view>
</view>
imge组件
重点:
1.image 组件可以写成单标签,也可以修改成 双标签 (单标签必须以 / 结尾)
2. image 组件默认有自己的大小 320 * 240
3.image 是一个行内块元素 (inline-block)
- src 下可以放远程地址或者是本地地址,本地地址可以使相对路径也可以是绝对路径
<image src="https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg"></image>
<image src="../../assets/timg.jpg" />
- 如果我们想通过调用 本地的相册,照相机获取图片则 需要一个按钮触发一个点击事件,在点击事件方法中调用 wx.chooseImage({ success: res => { } })方法
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
src | string | 否 | 图片资源地址 | 1.0.0 | |
mode | string | scaleToFill | 否 | 图片裁剪、缩放的模式 | 1.0.0 |
webp | boolean | false | 否 | 默认不解析 webP 格式,只支持网络资源 | 2.9.0 |
lazy-load | boolean | false | 否 | 图片懒加载,在即将进入一定范围(上下三屏)时才开始加载 | 1.5.0 |
show-menu-by-longpress | boolean | false | 否 | 开启长按图片显示识别小程序码菜单 | 2.7.0 |
binderror | eventhandle | 否 | 当错误发生时触发,event.detail = {errMsg} | 1.0.0 | |
bindload | eventhandle | 否 | 当图片载入完毕时触发,event.detail = {height, width} | 1.0.0 |
mode一些值:
值 | 说明 | 最低版本 |
---|---|---|
scaleToFill | 缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素 | |
aspectFit | 缩放模式,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。 | |
aspectFill | 缩放模式,保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。 | |
widthFix | 缩放模式,宽度不变,高度自动变化,保持原图宽高比不变 |
input组件
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
value | string | 输入框的初始内容 | 1.0.0 | ||
type | string | text | 否 | input 的类型 | 1.0.0 |
password | boolean | false | 否 | 是否是密码类型 | 1.0.0 |
placeholder | string | 是 | 输入框为空时占位符 | 1.0.0 | |
placeholder-style | string | 是 | 指定 placeholder 的样式 | 1.0.0 | |
placeholder-class | string | input-placeholder | 否 | 指定 placeholder 的样式类 | 1.0.0 |
disabled | boolean | false | 否 | 是否禁用 | 1.0.0 |
maxlength | number | 140 | 否 | 最大输入长度,设置为 -1 的时候不限制最大长度 | 1.0.0 |
cursor-spacing | number | 0 | 否 | 指定光标与键盘的距离,取 input 距离底部的距离和 cursor-spacing 指定的距离的最小值作为光标与键盘的距离 | 1.0.0 |
focus | boolean | false | 否 | 获取焦点 | 1.0.0 |
confirm-type | string | done | 否 | 设置键盘右下角按钮的文字,仅在type='text’时生效 | 1.1.0 |
confirm-hold | boolean | false | 否 | 点击键盘右下角按钮时是否保持键盘不收起 | 1.1.0 |
cursor | number | 是 | 指定focus时的光标位置 | 1.5.0 | |
selection-start | number | -1 | 否 | 光标起始位置,自动聚集时有效,需与selection-end搭配使用 | 1.9.0 |
selection-end | number | -1 | 否 | 光标结束位置,自动聚集时有效,需与selection-start搭配使用 | 1.9.0 |
adjust-position | boolean | true | 否 | 键盘弹起时,是否自动上推页面 | 1.9.90 |
hold-keyboard | boolean | false | 否 | focus时,点击页面的时候不收起键盘 | 2.8.2 |
bindinput | eventhandle | 是 | 键盘输入时触发,event.detail = {value, cursor, keyCode},keyCode 为键值,2.1.0 起支持,处理函数可以直接 return 一个字符串,将替换输入框的内容。 | 1.0.0 | |
bindfocus | eventhandle | 是 | 输入框聚焦时触发,event.detail = { value, height },height 为键盘高度,在基础库 1.9.90 起支持 | 1.0.0 | |
bindblur | eventhandle | 是 | 输入框失去焦点时触发,event.detail = {value: value} | 1.0.0 | |
bindconfirm | eventhandle | 是 | 点击完成按钮时触发,event.detail = {value: value} | 1.0.0 | |
bindkeyboardheightchange | eventhandle | 是 | 键盘高度发生变化的时候触发此事件,event.detail = {height: height, duration: duration} | 2.7.0 | |
auto-focus | boolean | false | 否 | (即将废弃,请直接使用 focus )自动聚焦,拉起键盘 | 1.0.0 |
scroll-view 局部滚动组件
- 事件监听 bindscrolltoupper bindscrolltolower bindscroll
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
scroll-x | boolean | false | 否 | 允许横向滚动 | 1.0.0 |
scroll-y | boolean | false | 否 | 允许纵向滚动 | 1.0.0 |
lower-threshold | number/string | 50 | 否 | 距底部/右边多远时,触发 scrolltolower 事件 | 1.0.0 |
scroll-top | number/string | 否 | 设置竖向滚动条位置 | 1.0.0 | |
scroll-left | number/string | 否 | 设置横向滚动条位置 | 1.0.0 | |
upper-threshold | number/string | 50 | 否 | 距顶部/左边多远时,触发 scrolltoupper 事件 | 1.0.0 |
scroll-into-view | string | 否 | 值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素 | 1.0.0 | |
scroll-with-animation | boolean | false | 否 | 在设置滚动条位置时使用动画过渡 | 1.0.0 |
enable-back-to-top | boolean | false | 否 | iOS点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向 | 1.0.0 |
enable-flex | boolean | false | 否 | 启用 flexbox 布局。开启后,当前节点声明了 display: flex 就会成为 flex container,并作用于其孩子节点。 | 2.7.3 |
scroll-anchoring | boolean | false | 否 | 开启 scroll anchoring 特性,即控制滚动位置不随内容变化而抖动,仅在 iOS 下生效,安卓下可参考 CSS overflow-anchor 属性。 | 2.8.2 |
bindscrolltoupper | eventhandle | 否 | 滚动到顶部/左边时触发 | 1.0.0 | |
bindscrolltolower | eventhandle | 否 | 滚动到底部/右边时触发 | 1.0.0 | |
bindscroll | eventhandle | 否 | 滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY} | 1.0.0 |
共同组件
属性 | 类型 | 描述 | 注解 | 最低版本 | |
---|---|---|---|---|---|
id | String | 组件唯一标识 | 整个页面唯一 | ||
class | String | 组件的样式类 | 在对应的wxss中定义的样式类 | ||
hidden | Boolean | 组件是否显示 | 所有组件默认显示 | ||
data-* | Any | 自定义属性 | 组件上触发事件时,会发送给事件处理函数 |
style String 组件的内联样式 可以动态设置内联样式
bind*/catch EventHandler 组件事件
wxss样式的三种书写方式
- 1.内联样式,style="",里面以键值对形式,以分号结束
- 2.页内样式
- 3.全局样式
<view style="font-size:18px; color:green;">HelloWorld</view>
<view class="box">HelloWorld</view>
<view class="container">HelloWorld</view>
优先级: 行内 > 页内 > 全局
WXSS的扩展-尺寸单位
尺寸单位
- rpx (responsive pixel):可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx
- 在iphone6上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px =750物理像素 1rpx = 0.5px = 1物理像素
WXSS的扩展 - 样式导入
为什么使用样式导入?
- 在某些情况下,我们可能会将样式分在多个wxss文件中,方便对样式的管理
- 这个时候,我们就可以使用样式导入,来让单独的wxss生效
我们可以在一个wxss中导入另一个wxss文件
- 1.使用**@import**进行导入
- 2.@import 后跟需要进行导入的外联样式表的相对路径(或者绝对路径也可以),用; 表示语句结束
导入的位置在哪里?
- 可以在app.wxss中导入这个样式
- 也可以在page.wxss导入这个样式
官方样式库
- 为了减少开发者样式的开发的工作量,小程序官方提供了WeUI.wxss基本样式库
Mustache语法
类似vue中的 mustache语法
wx:if 与 hidden公共属性的区别
- hidden : 将一个组件隐藏起来时,该组件依然是存在{ display:none}
- wx:if : 将一个组件隐藏起来,该组件根本不存在(压根没有创建)
- 选择:
- 如果现实和隐藏切换的频率非常高,选择使用hidden
- 如果现实和隐藏切换的频率非常低,那么选择 wx: if
block标签
什么是block标签?
- 某些情况下,我们需要使用wx:if 或者 wx:for时 ,可能需要包裹一组组件标签
- 我们希望对这一组组件标签进行整体的操作,这个时候怎么办呢?
- 使用block包裹,优点: 性能更高,代码更易阅读
列表渲染 -item / index 名称(wx:for)
默认情况下,item-index的名字是固定的
- 但是某些情况下,我们可能想使用其他名称
- 或者当出现多层遍历的时候,名字会重复
这个时候,我们可以指定item和index的名称
<block wx:for="{{movies}}" wx:for-item="moviesItem">
<block wx:for="{{moviesItem}}">
<view> {{item}}</view>
</block>
</block>
列表渲染 -key作用
我们看到,使用wx:for时 ,会报一个警告
- 这个提示告诉我们可以添加一个key来提高性能
为什么需要这个key属性呢
- 这个其实和小程序也使用了虚拟DOM有关系,类似于Vue React
当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点
- 我们希望可以在B和C之间加一个F,Diff算法默认执行起来时这样的
- 即把C更新成F , D更新成C , E更新成D,最后再插入E 是不是很没有效率
所以我们需要使用key来给每个节点做一个唯一的标识
- Diff算法就可以正确的识别此节点
- 找到正确的位置区插入新的节点
因此key 的作用主要是为了高效的更新虚拟DOM
个人理解:相当于有一堆苹果我找来了一堆盒子来装他们,我把盒子排成一排,每一个盒子装一个苹果,装完后你又掏出一个特别大的苹果给我,我想把这个大苹果放在这一排盒子的最前面,当没有key的时候,就相当于我不带脑子,把第一个盒子里的苹果拿出来放在第二个,第二个盒子苹果拿出来放第三个,以此类推,然后将这个最大苹果放在第一个盒子里,最后一个苹果没有盒子装,我又拿了个盒子装上他 放在最后一个。 此时会发现我把所有的苹果都拿出来了一次。 如果有key 就相当于,我直接拿来一个盒子装上这个大苹果,然后将他排在第一个位置
模板template用法
wxml提供模板,可以在模板中定义代码片段,在不同的地方调用,是一种wxml代码的复用机制
- 使用 name属性,作为模板的名字,然后在
<template/>
内定义代码片段 - 定义的使用使用name 使用的时候通过 is 属性,在data属性中定义需要用到的变量,因为是变量因此需要用胡子语法包裹
wxml的导入方式有两种方法
import 导入:
- 1.主要是导入template
- 2.特点:不能进行递归导入
include引入:
- 1.将公共的wxml的组件抽取到一个文件中
- 2.特点:不能导入 template/wxs, 可以进行递归导入
WXS模块
WXS是小程序的一套脚本语言,结合wxml,可以构建出页面的结构
为什么要设计WXS语言呢?
- 在WXML中是不能直接调用Page/Component中定义的函数的
- 但是某些情况,我们可以希望使用函数来处理WXML中的数据(类似vue中的过滤器),这个时候就使用WXS了
wxs使用的限制和特点
- WXS的运行环境和其他JavaScript代码是个例的,wxs中不能调用其他JavaScript文件中定义的函数,也不能调用小程序提供的API
- WXS函数不能作为组件的事件回调
- 由于运行环境的差异,在IOS设备上小程序内的WXS比Javascript快2-20倍,Android设备两者无差异
外部wxs文件定义
var message = 'Hello World';
var name = 'CoderWang';
var sum = function(num1, num2) {
return num1 + num2
};
// console.log(sum(1,6))
module.exports = {
message: message,
name: name,
sum:sum
}
内部引用
<wxs src="./wxs.wxs" module="info" />
<view>
{{info.message}}===
{{info.name}}====
{{info.sum(1,2)}}
</view>
注意: 此处路径只能是相对路径,且必须由module属性给这个wxs对象命名,这个是wxs抽取出去的写法
内部写法是直接一个双标签,定义module属性,内部使用wxs去操作,wxml中 通过 module定义的名字 点的方式去拿到定义i的数据,方法等
事件处理
某些组件会有自己特性的事件类型,大家可以在使用组件时候查看 具体的文档
- 比如input有 bindinput / bindblur / bindfocus等
- 比如scroll-view有 bindscrolltowpper / bindscrolltotower 等
这里我们讨论几个组件都有的,并且也是比较常见的事件类型
touchstart / touchmove / touchend / touchcancel / tap / longpress / longtap(推荐使用 longpress事件代替)
两个注意点:
- Tochcancle 在某些特定场景下才会触发(比如来电打断)
- tap事件 和 longpress 事件通常只触发其中一个
事件对象的介绍
属性 | 类型 | 说明 | 基础库版本 |
---|---|---|---|
type | String | 事件类型 | |
timeStamp | Integer | 事件生成时的时间戳 | |
target | Object | 触发事件的组件的一些属性值集合 | |
currentTarget | Object | 当前组件的一些属性值集合 | |
mark | Object | 事件标记数据 |
touches 和 changedTouches 区别
- 1.在touchend中不同
- 2.多手指触摸时不同
touches 记录着屏幕多少点正在被触摸
changedTouches 记录屏幕哪些点发生了改变
因此当第一次点上去的不离开,两者相等,一旦离开则 touches 为空,changedTouches 为还有一个对象。 当开始一个手指点上去则两者相同,后来又触发一次事件,又有两个手指点上去 此时 touches 有三个对象, 而changedTouches 只有两个,因为只有后来多了两个点,也就是变化的点
currentTarget 和 target 区别
- currentTarget 记录的是触发事件的 view (outer)
- 冒泡到的地方
- target 记录的是产生事件的view (inner)
- 点击的地方
在事件处理函数中拿到index和 item
- 绑定事件的通过 可以绑定属性 data-index=“index” 、 data-item=“item”
事件冒泡和事件捕获
当界面产生一个事件时,事件分为捕获阶段和冒泡阶段
事件捕获
- 外到内依次捕获
事件冒泡
- 内到外 依次冒泡
bind 和 catch区别:
- bind:一层层传递 , catch阻止事件的进一步传递
1.捕获阶段触发事件 使用 capture-bind:tap 的方式 注意需要使用: 不然无法捕获
2.当点击触发一个事件的时候,内部是先从最外层进行事件捕获,一层一层捕获到最内层,然后从最内层一层一层冒泡到最外层,这是一条顺序链,期间任何一处 使用 catch触发,而不用bind则会阻止事件进一步捕获或者是冒泡
组件化开发
类似于页面,自定义组件也是有 json wxml wxss js4个文件组成
- 按照好的编程习惯,我们会先在根目录下创建一个文件夹components,里面存放我们之后自定义的公共组件
- 常见一个自定义组件my-cpn : 包含对应的四个文件
自定义组件的步骤:
- 首先需要在json文件中进行自定义组件声明(将component字段设为 true 才会是这一组文件为自定义组件)
- 在WXML中编写属于我们组件自己的模板
- 在wxss中编写属于我们组件自己的相关样式
- 在js文件中可以定义数据或组件内部的相关逻辑
自定义组件使用的步骤
-
在使用的页面的json文件中进行一个声明
-
{ "usingComponents": { "my-cpn":"/components/my-cpn/my-cpn" } }
-
以键值对形式传入 到usingComponents中 键是 之后使用组件的标签名,值是路径 , 可以相对路径,也可以绝对路径
一些注意点
- 标签名只能是小写字母 ,中划线,下划线的组合
- 自定义组件也是可以引用自定义组件的,引用方法类似于页面引用自定义组件的方式(使用usingComponents字段)
- 自定义组件和页面所在项目根目录不能以 'wx-'为前缀,否则容易出错
- 如果在app.json的usingComponents声明某个组件,那么所有页面和 组件可以直接使用该组件
组件的样式细节
组件内的样式对外部样式的影响
- 结论一:组件内的class样式,只对组件wxml内的节点生效,对于引用组件的Page页面不生效
- 结论二:组件内不能使用id选择器,属性选择器,标签选择器
外部样式对组件内样式的影响
- 结论一:外部使用class的样式,只对外部wxml的class生效,对组件内是不生效的
- 结论二:外部使用了id选择器,属性选择器不会对组件内产生影响
- 结论三:外部使用了标签选择器,会对组件内产生影响
整体结论:
- 组件内的class样式和组件外的class样式,默认是有一个隔离效果的
- 为了防止样式的错乱,官方不推荐使用id,属性,标签选择器
样式的相互影响
如何让class可以相互影响
- 在Component对象中,可以传入一个option属性,其中options属性中有一个stylesolation(隔离)属性,stylesolation有三个取值
- isolate表示启用样式隔离,在自定义组件内外,使用class指定的样式将不会相互影响(默认)
- apply-shared 表示页面wxss样式将影响到自定义组件,但自定义组件wxss中指定的样式不会影响页面
- shared表示wxss样式将影响到自定义组件,自定义组件wxss中指定的样式也影响页面的其他设置
组件和页面通信
很多情况下,组件内展示的内容(数据,样式,标签),并不是在组件内写死的,而且可以由使用者来决定
页面 --------> 组件
- 数据:properties 样式:externalClasses 标签: slot
想组件传递数据- properties
参考vue的 props
给组件传递数据:
- 大部分情况下,组件只负责布局和样式,内容是由使用组件的对象决定的
- 所以,我们经常需要从外部传递数据给我们的组件,让我们的组件进行展示,如何传递呢
- 使用properties属性
支持的类型
- String Number Boolean
- Object Array null (不限制类型)
// 组件内
properties: {
title:{
type:String,
value:'HELLO'
}
}
// 页面内
<my-properties title="{{message}}" />
<my-properties title="你好呀" />
<my-properties title="helloWorld" />
向组件传递样式-externalClasses
给组件传递样式
-
有时候我们不希望将样式在组件内固定不变,而是外部可以决定样式
-
这个时候我们可以使用externalClasses属性
1.在Component对象中,定义externalClasses属性
2.在组件内的wxml中使用externalClasses属性中的class
3.在页面中传入对应的class,并且给这个class设置样式
组件使用 externalClasses 【与properties同级】, 他对应一个数组,数组的值就是页面传入的属性名,并且这个属性名要在组件页面上添加到对应的元素的class上,页面添加该属性,传入一个定义好的class类名,即可将这个class类名的样式传递给了这个组件响应的class上
/* 组件内使用这个类名 */
<view class="title boxstyle">{{title}}</view>
/* 组件内注册添加 externalClasses 他对应一个数组 */
externalClasses:[
'boxstyle'
]
/* 页面内使用externalClasses 注册的名字做属性名,接收一个自己定义好的样式类 */
<my-cpn boxstyle="border" />
/*页面样式中给这个样式类添加好样式*/
.border{
color: yellow!important;
background-color: #ccc;
border:2px solid #eee;
}
组件向外传递事件-自定义事件
1.组件内监听事件,需要页面做出相应的操作,则组件内事件触发的时候需要通知都页面,因此需要发射一个事件,类似vue中的this.$emit( )
2.组件内发射事件使用 this.triggerEvent( ‘发射的事件名’, ‘需要传递过去的参数’,[option])
3.页面中通过 bind:‘事件名’ = 操作函数 绑定事件,并且对应触发一个方法
4.此时这个方法中就可以操作 页面中的数据了,并且函数触发,说明组件内的事件触发了,当然组件传递的参数,这个存在这个方法的 event参数中,在event.detail中
页面直接调用组件修改数据/方法
页面通过this.selectComponent()方法去拿到这个组件对象 ,括号内可以使class选择器或者 id选择器 类似 querySelecter()
- 拿到对象后虽然后通过对象 . setData方法直接修改组件内数据,但是不建议这么做,修改对应组件的数据还是需要在对象组件内去处理
- 因此我们在组件定义一个想修改数据的方法,然后通过调用这个方法去修改数据
插槽
slot翻译为插槽
- 在生活中很多地方都有插槽,电脑的usb插槽,插板当中的电源插槽
- 插槽的目的是让我们远离的设备具备更多的扩展性
插槽用法类似于vue中 slot
一般使用
- 直接组件中使用一堆 slot标签占位
- 页面中在组件标签内添加内容标签就会匹配到这个slot标签中
多slot使用
- 首先组件内的slot需要给一个 name属性,用于后续页面中通过slot="***" 去匹配这个slot
- 虽然上面一步完成,但是还是不能匹配,因为我们还需要在组件的json配置中添加上multipleSlots:true
组件Component
传入对象,对象中可传参数:
- properties 定义传入的属性
- data 定义内部的属性
- methods 定义方法
- options 额外配置
- styleIsolation : “shared” 【是否隔离组件内样式跟页面的样式】
- multipleSlots : true 【多插槽使用的时候需要设置为true】
- externalClasses 引入外部样式
- 跟properties相似,页面通过属性传值,值是页面的一个样式类,组件在externalClasses中接收,并将这个接收的属性作为class类绑定到组件的元素上
- observers 属性和数据监听
- 类似vue的 watch,对象中传入函数,函数默认传参 newValue 注意组件内这个属性没有 oldValue
- pageLifetimes 页面生命周期
- 可以监听所在页面的生命周期
- show() 页面显示执行
- hode() 页面隐藏执行
- resize() 页面尺寸发生变化执行
- lifetimes 组件生命周期
- created 组件被创建执行
- attached 组件被添加到页面中执行
- moved 组件被移动到节点树另一个位置时候执行
- detached 组件被移除时候执行
系统API(网络请求)
网络请求-基本使用
微信提供了专属的API接口,用于网络请求:wx.request(Object object)
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
url | string | 是 | 开发者服务器接口地址 | ||
data | string/object/ArrayBuffer | 否 | 请求的参数 | ||
header | Object | 否 | 设置请求的 header,header 中不能设置 Referer。 content-type 默认为 application/json | ||
timeout | number | 否 | 超时时间,单位为毫秒 | 2.10.0 | |
method | string | GET | 否 | HTTP 请求方法 | |
dataType | string | json | 否 | 返回的数据格式 | |
responseType | string | text | 否 | 响应的数据类型 | 1.7.0 |
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
展示弹窗
主要有 showToast showModel showLoading showActionSheet
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
title | string | 是 | 提示的内容 | ||
icon | string | ‘success’ | 否 | 图标 | |
image | string | 否 | 自定义图标的本地路径,image 的优先级高于 icon | 1.1.0 | |
duration | number | 1500 | 否 | 提示的延迟时间 | |
mask | boolean | false | 否 | 是否显示透明蒙层,防止触摸穿透 | |
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.icon 的合法值
值 | 说明 | 最低版本 |
---|---|---|
success | 显示成功图标,此时 title 文本最多显示 7 个汉字长度 | |
loading | 显示加载图标,此时 title 文本最多显示 7 个汉字长度 | |
none | 不显示图标,此时 title 文本最多可显示两行,1.9.0及以上版本支持 |
示例代码
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000
})
注意
- wx.showLoading 和 wx.showToast 同时只能显示一个
- wx.showToast 应与 wx.hideToast 配对使用
页面分享
分享是小程序扩散的一种重要方式,小程序中又两种风险方式:
- 点击右上角菜单按钮,之后点击转发
- 点击摸一个按钮直接转发
当我们转发给好友一个小程序时,通常小程序中会显示一些信息
- 如何决定这些信息的展示呢 通过 onShareAppMessage
每个页面都有各种 生命周期函数,data等,包括onShareAppMessage(){ }
这里面
onShareAppMessage(Object object)
监听用户点击页面内转发按钮(button 组件 open-type="share"
)或右上角菜单“转发”按钮的行为,并自定义转发内容。
注意:只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮
onShareAppMessage(){ }函数需要返回一个 对象
对象中的参数:
- title 转发界面的标题
- path 别人点击转发内容进入的路径
- imageUrl 转发界面的图片
小程序的登录流程
- 1.调用wx.login 获取code
- 2.调用wx.request发送code到我们自己的服务器(我们自己的服务器会返回一个登录态的标识比如token)
- 3.将登录态的标识token进行存储,一边下次使用
- 4.请求需要登录态标识的接口时,携带token
演练接口 http://123.207.32.32:3000/login
页面跳转
页面的跳转有两种方式,通过navgator 组件和通过wx的API跳转
navigator 组件主要就是用于界面的跳转
<navigator url="/pages/detail/detail">跳转</navigator>
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
target | string | self | 否 | 在哪个目标上发生跳转,默认当前小程序 | |
url | string | 否 | 当前小程序内的跳转链接 | ||
open-type | string | navigate | 否 | 跳转方式 | |
delta | number | 1 | 否 | 当 open-type 为 ‘navigateBack’ 时有效,表示回退的层数 | |
app-id | string | 否 | 当target="miniProgram" 时有效,要打开的小程序 appId | ||
path | string | 否 | 当target="miniProgram" 时有效,打开的页面路径,如果为空则打开首页 | ||
extra-data | object | 否 | 当target="miniProgram" 时有效,需要传递给目标小程序的数据,目标小程序可在 App.onLaunch() ,App.onShow() 中获取到这份数据。详情 | ||
version | string | release | 否 | 当target="miniProgram" 时有效,要打开的小程序版本 | |
hover-class | string | navigator-hover | 否 | 指定点击时的样式类,当hover-class="none" 时,没有点击态效果 | |
hover-stop-propagation | boolean | false | 否 | 指定是否阻止本节点的祖先节点出现点击态 | |
hover-start-time | number | 50 | 否 | 按住后多久出现点击态,单位毫秒 | |
hover-stay-time | number | 600 | 否 | 手指松开后点击态保留时间,单位毫秒 | |
bindsuccess | string | 否 | 当target="miniProgram" 时有效,跳转小程序成功 | ||
bindfail | string | 否 | 当target="miniProgram" 时有效,跳转小程序失败 | ||
bindcomplete | string | 否 | 当target="miniProgram" 时有效,跳转小程序完成 |
navigator组件的 open-type的取值
值 | 说明 | 最低版本 |
---|---|---|
navigate | 对应 wx.navigateTo 或 wx.navigateToMiniProgram 的功能 | |
redirect | 对应 wx.redirectTo 的功能 | |
switchTab | 对应 wx.switchTab 的功能 | |
reLaunch | 对应 wx.reLaunch 的功能 | |
navigateBack | 对应 wx.navigateBack 的功能 | |
exit | 退出小程序,target="miniProgram" 时生效 |
- redirect:关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到tabbar页面,并且 不能返回(不是一个压栈)
- switchTab: 跳转到tabBar页面,并关闭其他所有非tabBar页面(需要在tabbar中定义)
- reLaunch: 关闭所有页面,打开应用中某个页面(直接展示某个页面,并且可以跳转到tabbar页面)
总结:
- 使用 navigator 组件 , 给一个url地址就可以跳转了,默认 open-type 为 navigate ,这个只是用新的页面层叠旧页面,原来的页面还在,此时可以左上角返回,或者 创建navigator 组件,定义open-type 为 navigateBack 就可以返回了
- 当使用redirect 时候,效果跟 navigate 一样,但是不是层叠旧页面 而是直接销毁其他页面,进入新页面,因此无法返回,使用 navigateBack 也不行
- 当使用 switchTab 相当于模拟了 点击tabbar操作,并且,无法返回
- 当使用 reLaunch 则是关闭所有页面,然后打开应用中的某个页面,跟redirect 不同的是 redirect是关闭当前页面,而reLaunch是 关闭所有页面
- 当然 open-type 属性中的navigateBack 中的delta 设置跳回哪一层, 1是返回上一层,2是返回上上层
- 当路由定义在了 tabBar中时候,不能通过 navigate 跳转 只能通过 switchTab去跳转
跳转过程中的数据传递
正向传递 使用 query字段
- 直接在url 后面拼接,进行传递
- 在对应onLoad中的 参数 option 中就会有传递的数据
点击返回,反向传递(没有直接的方法)
- 可以在生命函数 onUnload 中传递数据
- onUnload函数是页面关闭的时候触发
- 在这个函数中调用 getCurrentPage( )可以拿到活跃的页面对象,
- 如果想拿到上一页的page对象,只需要使用 getCurrentPage( )[getCurrentPage( )-2]即可
- 然后就可以调用page对象的 setData({ }) 方法去更改对象中的数据了
在js中定义跳转
方法基本和组件的方式相似
- navigateTo
- redirectTo
- 返回的时候 则是 navigateBack
总结
- 使用 按钮等定义事件,用户触发事件后调用定义好的函数,定义函数中设置navigateTo, redirectTo ,参数传入一个对象,对象中传入跳转的 url
- 返回的话 使用 navigateBack 参数对象中 添加属性 delta 可以设置返回上几层