微信小程序 之 原生开发
目录
一、前期预备
1. 预备知识
2. 注册账号 - 申请AppID
3. 下载小程序开发工具
4. 小程序项目结构
5. 小程序的MVVM架构
二、创建小程序项目
1. 查看注册的appId
2. 创建项目
3. 新建页面
01 - 创建text页面文件夹
02 - 新建text的page
03 - 在app.json中配置
4. 开发初体验
01 - text.wxml
02 - text.js
03 - 效果
三、小程序的架构和配置
1. 小程序的架构模型
01 - 宿主环境
02 - 双线程模型
2. 小程序的配置文件
01 - project.config.json
02 - sitemap.json
03 - app.json
代码
效果
04 - (page).json
代码
效果
四、注册小程序 – App函数 - app.js
作用一 : 判断打开场景
01 - 常见场景
02 - 确定场景
代码
效果
作用二 : 定义全局App的数据
app.js
page.js
效果
作用三 : 生命周期函数
五、注册页面 – Page函数 - (page).js
0. 生命周期
1. 发送网络请求
2. 初始数据
3. 绑定事件函数
wxml
js
4. 其他的监听
01 - 下拉刷新
logs.json
logs.js
效果
02 - 上拉加载更多
logs.json
logs.js
logs.wxml
效果
03 - 页面滚动
六、常见的内置组件
Text : 文本组件
Button : 按钮组件
基本用法
open-type属性
获取用户信息
wxml
js
获取用户手机
wxml
js
View : 视图组件
ScrollView滚动组件
上下滚动
wxml
css
js
左右滚动
wxml
css
js
Image : 图片组件
基本使用
使用手机本地图片 wx.chooseMedia
wxml
js
Input : 组件
wxml
js
组件的共同属性
七、小程序基础语法
1. Wxss
01 - 样式写法
02 - 选择器
03 - 尺寸单位
2. Wxml
01 - 逻辑判断
03 - block
04 - 列表渲染
wx:for
item - index
key
3. Wxs
01 - 概念
02 - 写法
写法一 : 直接写在标签内
写法二 : 独立的文件,通过src引入
定义format.wxs
wxml
八、小程序的事件处理
1. 组件事件类型
2. 事件对象event
01 - currentTarget && target
wxml
wxss
js
02 - touches && changedTouches
区别一 : touchend中不同
区别二 : 多手指触摸时不同
03 - 事件参数的传递
wxml
js
04 - 事件参数的传递的例子
wxml
wxss
js
效果
3. 事件冒泡 && 事件捕获
4. 获取元素的宽高等
九、小程序的组件化开发
1. 概念
2. 创建并使用组件
01 - 创建
02 - 配置
03 - 引入组件
局部注册组件
全局注册组件
04 - 使用组件
05 - 注意事项
3. 组件的样式细节
01 - 组件内的样式 对 外部样式 的影响
02 - 外部的样式 对 组件内样式 的影响
03 - 如何让class可以相互影响
4. 组件的通信
01 - 向组件传递数据 - properties
页面定义
组件接收
02 - 向组件传递样式 - externalClasses
页面定义
页面传递
组件接收
组件使用
03 - 组件向外传递事件
组件定义
组件传递
页面监听
页面处理
04 - 页面直接调用组件方法
组件定义
页面定义
页面使用
5. 组件的插槽
01 - 单个插槽
组件
页面
效果
02 - 具名插槽
组件定义
组件配置
页面使用
03 - 解决默认值问题
组件
样式
6. 组件中的混入 - behaviors
01 - 共享的代码
02 - 组件中使用
7. 组件的生命周期
01 - 概念
02 - 组件所在页面的生命周期
8. 组件Component构造器总结图
十、小程序系统API调用
1. 网络请求
01 - API参数
02 - API使用
03 - API封装
封装成函数
封装
使用
封装成类
封装
使用
04 - 网络请求域名配置
2. 展示弹窗效果
01 - showToast
效果
代码
02 - showLoading
效果
代码
03 - showModal
效果
代码
04 - showActionSheet
效果
代码
方式一
方式二
4. 获取设备信息 wx.getSystemInfo
5. 获取位置信息 wx.getLocation
01 - 授权
02 - 获取
6. Storage存储
01 - 同步
02 - 异步
十一、页面跳转
1. 通过wx的API跳转
00 - switchTab - 跳转到 tabBar 页面
03 - 页面跳转 - 数据传递(一)
首页 => 详情页
详情页 => 首页
04 - 页面跳转 - 数据传递(二)
首页 => 详情页
详情页 => 首页
01 - 跳转到 tabBar 页面
02 - 跳转到 普通 页面
03 - 返回 上一个 页面
十二、小程序登录解析
1. 概念
01 - openid
02 - unionid
03 - 用户身份多平台共享
2. 登录流程
3. 代码
十三、代码上传到Gitee
1. 创建远程仓库
2. 配置远程仓库
01 - 本地点击版本管理
02 - 添加远程仓库
03 - 设置用户名和邮箱
04 - 设置网络和认证
3. 推送代码到远程仓库
01 - 首次推送
02 - 修改后推送
推送到本地仓库
拉取远程仓库代码
推送到远程仓库
一、前期预备
1. 预备知识
小程序的核心技术主要是三个:
- 页面布局:WXML,类似HTML
- 页面样式:WXSS,几乎就是CSS(某些不支持,某些进行了增强,但是基本是一致的)
- 页面脚本:JavaScript+WXS(WeixinScript)
2. 注册账号 - 申请AppID
网址 : 微信小程序
3. 下载小程序开发工具
网址 : 微信开发者工具下载地址与更新日志 | 微信开放文档
4. 小程序项目结构
5. 小程序的MVVM架构
Vue的MVVM和小程序MVVM对比
MVVM :
- DOM Listeners: ViewModel层可以将DOM的监听绑定到Model层
- Data Bindings: ViewModel层可以将数据的变量, 响应式的反应到View层
- MVVM架构将 命令式编程 转移到 声明式编程
二、创建小程序项目
1. 查看注册的appId
网址 : 小程序
2. 创建项目
3. 新建页面
01 - 创建text页面文件夹
02 - 新建text的page
03 - 在app.json中配置
可能会自动注册完成
ps : 也可以反向注册,在这里直接配置,文件夹会自动生成
4. 开发初体验
01 - text.wxml
<!--pages/text/text.wxml-->
<!-- 1. 普通文本 -->
<view>text页面</view><!-- 2. 数据绑定,使用 {{}} 这个语法 -->
<view>{{message}}</view><!-- 3. 列表渲染 -->
<block wx:for="{{movies}}" wx:key="item"><view>item : {{item}} => index: {{index}}</view>
</block><!-- 4. 事件监听 -->
<view style="text-align: center">当前计数 : {{counter}}</view>
<button bindtap="increment">+1</button>
<button bindtap="decrement">-1</button>
02 - text.js
直接修改data中的数据,不会引起页面的刷新
小程序和react中都不会,只有vue劫持了属性才能直接操作
ps : 修改data并且希望页面重新渲染,必须使用 this.setData()
// pages/text/text.js
Page({/*** 页面的初始数据*/data: {// 1. 数据绑定,{{}} 语法message: 'star',// 2. 列表渲染数据movies: ['迪迦大战肯德基', '图图和小新抢东西吃'],// 3. 计数器参数counter: 0},// 监听计数器增加按钮触发increment() {// 此方法修改后的数据不会在页面上响应// this.data.counter += 1this.setData({counter: this.data.counter + 1})},// 监听计数器减少按钮触发decrement() {this.setData({counter: this.data.counter - 1})},
})
03 - 效果
三、小程序的架构和配置
1. 小程序的架构模型
01 - 宿主环境
小程序的宿主环境 => 微信客户端
ps : 宿主环境为了执行小程序的各种文件:wxml文件、wxss文件、js文件
02 - 双线程模型
- 当小程序基于 WebView 环境下时,WebView 的 JS 逻辑、DOM 树创建、CSS 解析、样式计算、Layout、Paint (Composite) 都发生在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿
- 以此为前提,小程序同时考虑了性能与安全,采用了目前称为「双线程模型」的架构
双线程模型 :
- WXML模块和WXSS样式运行于 渲染层,渲染层使用WebView线程渲染(一个程序有多个页面,会使用多个WebView的线程)
- JS脚本(app.js/home.js等)运行于 逻辑层,逻辑层使用JsCore运行JS脚本
- 这两个线程都会经由微信客户端(Native)进行中转交互
- 注 : wxs是和渲染层呆在一起的
2. 小程序的配置文件
01 - project.config.json
项目配置文件 => 比如项目名称、appid等
网址 : 项目配置文件 | 微信开放文档
02 - sitemap.json
小程序搜索相关的
网址 : sitemap 配置 | 微信开放文档
03 - app.json
全局配置
网址 : 全局配置 | 微信开放文档
- pages : 页面路径列表
- 用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息
- 小程序中所有的页面都是必须在pages中进行注册的
- 全局配置 - pages | 微信开放文档
- window : 全局的默认窗口展示
- 用户指定窗口如何展示, 其中还包含了很多其他的属性
- 全局配置 - window | 微信开放文档
- tabBar : 顶部tab栏的展示
- 全局配置 - tabBar | 微信开放文档
代码
{"pages": [// 默认显示的页面"pages/text/text","pages/index/index","pages/logs/logs"],"window": {// 下拉 loading 的样式,仅支持 dark 黑色 / light 白色// 需要到页面的.json中加入 "enablePullDownRefresh": true , 开启即可// 最好别在全局开启下拉刷新"backgroundTextStyle": "dark",// 导航栏背景颜色"navigationBarBackgroundColor": "#f00",// 导航栏标题文字内容"navigationBarTitleText": "Weixin",// 导航栏标题颜色,仅支持 black / white"navigationBarTextStyle": "black"},// 底部导航按钮"tabBar": {// 文字默认的颜色"color":"#fff",// 选中时文字的颜色"selectedColor":"#ff8189",// 导航是一个数组"list": [{// 页面路径"pagePath": "pages/index/index",// 文本"text": "首页",// 默认显示的图标"iconPath": "assets/images/tabbar/home.png",// 选中时显示的图标"selectedIconPath": "assets/images/tabbar/home_active.png"},{"pagePath": "pages/text/text","text": "记录","iconPath": "assets/images/tabbar/category.png","selectedIconPath": "assets/images/tabbar/category_active.png"}]},// 表明启用新版的组件样式"style": "v2",// 配置搜索相关文件,基本不需更改"sitemapLocation": "sitemap.json"
}
效果
04 - (page).json
页面配置
每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置
页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项
网址 : 页面配置 | 微信开放文档
代码
{// 是否使用组件"usingComponents": {// 需要在这里配置},// 页面顶部标题文字"navigationBarTitleText": "冲啊",// 页面顶部标题颜色"navigationBarTextStyle": "white",// 页面顶部背景颜色"navigationBarBackgroundColor": "#0f0",// 是否开启下拉刷新 // Page.js 中,onPullDownRefresh 开启这个,可以监听到是否下拉刷新了"enablePullDownRefresh": true,
}
效果
四、注册小程序 – App函数 - app.js
每个小程序都需要在 app.js 中调用 App 函数 注册小程序示例
网址 : App(Object object) | 微信开放文档
- 在注册时, 可以绑定对应的生命周期函数
- 在生命周期函数中, 执行对应的代码
注册App时,一般做如下事情 :
- 监听生命周期函数,在生命周期中执行对应的业务逻辑,比如在某个生命周期函数中进行登录操作或者请求网络数据
- 判断小程序的进入场景
- 因为App()实例只有一个,并且是全局共享的(单例对象),所以我们可以将一些共享数据放在这里
作用一 : 判断打开场景
01 - 常见场景
小程序的打开场景较多 :
- 常见的打开场景
- 群聊会话中打开
- 小程序列表中打开
- 微信扫一扫打开
- 另一个小程序打开
- 场景值 : 微信开放文档 - 场景值列表
02 - 确定场景
在 onLaunch 和 onShow 生命周期回调函数中,会有options参数,其中有scene值
代码
// app.js
App({/*** 生命周期回调——监听小程序初始化。* 小程序初始化时触发,只有执行一次*/onLaunch(options) {console.log('onLaunch =>', 'scene :', options.scene);// 登录wx.login({success: res => {// 发送 res.code 到后台换取 openId, sessionKey, unionId}})},/*** 生命周期回调——监听小程序启动或切前台* 每次打开小程序都会执行*/onShow(options) {console.log('onShow =>', 'scene :', options.scene);// 可根据场景值,跳转到对应的页面wx.navigateTo({// url: 'url',})},onHide() {console.log('onHide => 隐藏~');}
})
效果
作用二 : 定义全局App的数据
注意 : 定义在全局的数据不会响应式
共享的数据通常是一些固定的数据
app.js
// app.js
App({// 定义的全局变量globalData: {token: '',userInfo: {name: 'coder',age: 18}},// 页面初始化调用的回调函数onLaunch(options) {// 登录wx.login({success: res => {console.log('code =>', res.code);// 发送 res.code 到后台换取 openId, sessionKey, unionIdthis.globalData.token = res.token || 'abcdefghijklmnopqrstuvwxyz'}})}
})
page.js
// pages/text/text.js
Page({// 页面加载的时候触发/*** 获取页面所需数据*/onLoad() {// 获取共享的数据// 1. 获取app实例对象const app = getApp()// 2. 从app实例对象中获取数据const token = app.globalData.tokenconst userInfo = app.globalData.userInfoconsole.log('userInfo :', userInfo);console.log('token :', token);// 3. 拿到token后发送网络请求// wx.request({// url: 'url',// token// })// 4. 展示数据到页面this.setData({userInfo})},/*** 页面的初始数据*/data: {userInfo: {}},
})
效果
作用三 : 生命周期函数
在生命周期函数中,完成应用程序启动后的初始化操作
- 比如登录操作
- 比如读取本地数据(类似于token,然后保存在全局方便使用)
- 比如请求整个应用程序需要的数据
这里简单写写,详细的登录操作在下方
// app.js
App({// globalDataglobalData: {userState: {openId: '',sessionKey: '',unionId: ''},userInfo: {}},// 页面初始化调用的回调函数onLaunch(options) {// 从本地获取用户状态信息,判断是否需要登录const userState = wx.getStorageSync('userState')// 如果不存在,则进行登录if (!userState || !userState.openId) {wx.login({success: res => {console.log('code =>', res.code);// 发送 res.code 到后台换取 openId, sessionKey, unionIdthis.getUserState(res.code)}})}},// 获取用户信息getUserState(code) {wx.request({// 填入请求地址url: 'url',code,success: (res) => {const { openId, unionId, sessionKey, userInfo } = res// 将登录成功的数据,保存在storage中wx.setStorageSync('userState', {openId,unionId,sessionKey,})wx.setStorageSync('userInfo', userInfo)// 将登录成功的数据,保存在globalData中this.globalData.userState = {openId,unionId,sessionKey,}this.globalData.userInfo = userInfo}})// }
})
五、注册页面 – Page函数 - (page).js
小程序中的每个页面, 都有一个对应的js文件, 其中调用 Page函数 注册页面示例
网址 : Page(Object object) | 微信开放文档
- 在注册时, 可以绑定初始化数据、生命周期回调、事件处理函数等
注册Page页面时,一般做如下事情 :
- 在生命周期函数中发送网络请求,从服务器获取数据
- 初始化一些数据,以方便被wxml引用展示
- 监听wxml中的事件,绑定对应的事件函数
- 其他一些监听(比如页面滚动、上拉刷新、下拉加载更多等)
0. 生命周期
网址 : 生命周期 | 微信开放文档
1. 发送网络请求
// logs.js
Page({data: {pagaData: {}},// 页面加载时促发onLoad() {const _this = this// 发送网络请求wx.request({url: 'www.baidu.com',success: (res) => {console.log(this, res);this.setData({pagaData: res.pagaData || {}})},error(err) {console.log(_this, err);}})}
})
2. 初始数据
// logs.js
Page({data: {// 定义初始化数据movies: ['葫芦娃大战喜羊羊', '蜡笔小新殴打图图'],},// 页面加载时促发onLoad() { }
})
3. 绑定事件函数
wxml
<!--logs.wxml-->
<view><button bindtap="handClick">事件触发</button><button>------</button><button bindtap="clickQuery"data-query="abc">触发并传递参数</button><button>------</button><button wx:for="{{btns}}"wx:key="*this"bindtap="btnsClick"data-index="{{index}}"data-item="{{item}}"style="background-color: {{item}};">{{item}} - {{index}}</button>
</view>
js
// logs.js
Page({data: {// 定义初始化数据btns: ['red', 'blue', 'green', 'pink', 'yellow'],},// 页面加载时促发onLoad() { },// 绑定事件handClick() {console.log('我被点击了');},// 传递参数clickQuery(e) {console.log('我被点击了,参数是 : ', e.target.dataset);},btnsClick(e) {console.log('循环出的按钮', e.target.dataset);}
})
4. 其他的监听
01 - 下拉刷新
logs.json
{"usingComponents": {},// 开启下拉刷新"enablePullDownRefresh": true
}
logs.js
// logs.js
Page({data: {},// 监听用户下拉刷新onPullDownRefresh() {console.log('用户下拉刷新');// 模拟网络请求setTimeout(() => {// api: 停止下拉刷新wx.stopPullDownRefresh({success: (res) => {console.log('成功关闭下拉刷新', res);},fail: (err) => {console.log('关闭失败', err);}})}, 1000);}
})
效果
02 - 上拉加载更多
logs.json
{"usingComponents": {},// 页面上拉触底事件触发时距页面底部距离,单位为px// 距离底部多少距离,触发"onReachBottomDistance": 100
}
logs.js
// logs.js
Page({data: {// 默认展示50条数据countsNum: 50,// 到达底部后,需要增加的数量countsSize: 40},// 监听页面是否滚动到达底部onReachBottom() {this.setData({// 到达底部后,增加countsNum: this.data.countsNum + this.data.countsSize})console.log('滚动到底部');}
})
logs.wxml
<!--logs.wxml-->
<view wx:for="{{countsNum}}" wx:key="*this">页面数据 : {{item}}
</view>
效果
03 - 页面滚动
// logs.js
Page({data: {// 定义初始化数据btns: ['red', 'blue', 'green', 'pink', 'yellow'],},// 页面加载时促发onLoad() { },// 页面滚动onPageScroll(e) {console.log(e); // 距离顶部的距离},
})
六、常见的内置组件
Text : 文本组件
Text组件 : 用于显示文本, 类似于span标签, 是行内元素
text | 微信开放文档
<!-- 基本用法 -->
<text>Hello world</text><!-- 使用js中定义的数据 -->
<text>{{message}}</text><!-- 长按可选择,可用来复制 -->
<text user-select>{{message}}</text><!-- 解码 -->
<text decode>></text>
Button : 按钮组件
Button组件用于创建按钮,默认块级元素
button | 微信开放文档
基本用法
<!-- 默认 => 独占一行 -->
<button>按钮</button><!-- size属性 => 变成了inline-block -->
<button size="mini">size属性</button><!-- type属性 => 可更改背景、颜色 -->
<button size="mini"type="default">文字颜色变绿</button>
<button size="mini"type="primary">背景颜色变绿</button>
<button size="mini"type="warn">文字颜色变红</button><!-- plain => 镂空效果 -->
<button size="mini"plain> 镂空效果,有边框 </button><!-- 禁用 -->
<button size="mini"disabled> 禁止交互 </button><!-- 加载效果 => 前方有个小圆圈在转,可动态绑定 -->
<button size="mini"loading='{{true}}'> 等待加载 </button>
open-type属性
open-type用户获取一些特殊性的权限,可以绑定一些特殊的事件
获取用户信息
wxml
<!-- 获取用户信息 -->
<button bindtap="getUserProfile">获取用户信息</button>
js
Page({getUserProfile(e) {// 推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认// 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗wx.getUserProfile({desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写// 点击允许success: (res) => {console.log('success', res);},// 点击拒绝fail: (err) => {console.log('fail', err);}})}
})
获取用户手机
wxml
<!-- 获取用户手机号 -->
<button open-type="getPhoneNumber"bindgetphonenumber="getPhoneNumber">获取用户手机号</button>
js
Page({getPhoneNumber(e) {// 如果点击了拒绝if (e.target.errMsg !== 'getPhoneNumber:ok') {return wx.showToast({title: '用户未同意授权手机号',icon: 'none'})}// 如果点击确认cosnt { code, encryptedData, iv } = e.target// 把数据传给后端,后端会去解密拿到手机号的wx.request({url: 'https://example.com/onLogin',data: {appId: '',openId: '',code,encryptedData,iv},method: "post",success: function (res) {console.log(res);}})}
})
View : 视图组件
View视图组件 : 块级元素,独占一行,通常用作容器组件,和div差不多
view | 微信开放文档
ScrollView滚动组件
scroll-view : 可以实现局部滚动
scroll-view | 微信开放文档
上下滚动
wxml
<!-- 固定高度,上下滚动,( y轴 : scroll-y ) -->
<scroll-view class="contain scroll-y"scroll-ybindscrolltoupper="scrollTop"bindscrolltolower="scrollBottom"bindscroll='scrollIng'><block wx:for="{{viewColors}}"wx:key="*this"><view class="box"style="background-color: {{item}}">{{item}}</view></block>
</scroll-view>
css
.contain {height: 300px;
}.box {height: 100px;color: white;font-weight: bold;
}
js
Page({data: {viewColors: ['red', 'pink', 'green', 'blue']},scrollTop() {console.log('到达顶部');},scrollBottom() {console.log('到达底部');},// 滚动中触发scrollIng({ detail }) {console.log(detail);}
})
左右滚动
注 : 若要开启flex布局,须加上enable-flex这个属性
wxml
<!-- 固定宽度,左右滚动,( x轴 : scroll-x ) -->
<scroll-view class="contain scroll-x"scroll-xenable-flexbindscrolltoupper="scrollLeft"bindscrolltolower="scrollRight"bindscroll='scrollIng'><block wx:for="{{viewColors}}"wx:key="*this"><view class="box"style="background-color: {{item}}">{{item}}</view></block>
</scroll-view>
css
.contain {display: flex;
}.box {/* 不压缩 */flex-shrink: 0;width: 150px;height: 150px;color: white;font-weight: bold;
}
js
Page({data: {viewColors: ['red', 'pink', 'green', 'blue']},scrollLeft() {console.log('到达左侧');},scrollRight() {console.log('到达右侧');},// 滚动中触发scrollIng({ detail }) {console.log(detail);// detail.deltaX > 0,往左滚动// detail.deltaX < 0,往右滚动}
})
Image : 图片组件
Image组件 : 用于显示图片
image | 微信开放文档
基本使用
<!-- image : 默认自带宽度和高度 => 320 * 240 --><!-- 根目录 : / 表示根目录,有些地方能用,有些不行 -->
<!-- <image src="/assets/images/zznh.png" /> --><!-- 加载本地图片 -->
<image src="../../assets/images/zznh.png" />
<!-- 加载网络图片 -->
<image src="https://uploadfile.bizhizu.cn/up/9d/8d/1e/9d8d1e3fba7895d13a639f464ef147b1.jpg.source.jpg" /><!-- 使用mode属性 -->
<image src="../../assets/images/zznh.png" mode="widthFix" />
使用手机本地图片 wx.chooseMedia
wxml
<!-- 选择手机本地图片,将本地图片展示出来 -->
<button bindtap="choseImage"type="primary">进入相册选择图片</button><image wx:if="{{imgUrl}}"src="{{imgUrl}}"style="width: 100%;"mode="widthFix" />
js
Page({data: {imgUrl: ''},choseImage() {// 选择本地图片wx.chooseMedia({// 最多可以选择的文件个数count: 1,// 只能拍摄图片或从相册选择图片mediaType: 'image',}).then(res => {if (res.errMsg !== 'chooseMedia:ok') returnconsole.log(res);const imageList = res.tempFiles || []const imgUrl = imageList[0].tempFilePath || ''this.setData({imgUrl})})}
})
Input : 组件
model:value => 双向绑定功能
wxml
<input type="text" model:value='{{message}}' />
js
Page({data: {message: 'abc'},
})
组件的共同属性
七、小程序基础语法
1. Wxss
01 - 样式写法
页面样式的三种写法:行内样式、页面样式、全局样式
优先级依次是:行内样式 > 页面样式 > 全局样式
02 - 选择器
权重
03 - 尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应,规定屏幕宽为750rpx
在iphone6上,屏幕宽度为375px,共有750个物理像素,1px === 2rpx
iphone6为标准,设计稿是375,1px === 2rpx => 设计稿16px,我们写32rpx
iphone6为标准,设计稿是750,1px === 1rpx => 设计稿20px,我们写20rpx
.view {/* 在375的设计稿中,200rpx === 100px */width: 200rpx;height: 200rpx;background-color: blue;line-height: 200rpx;text-align: center;color: #fff;
}
2. Wxml
01 - 逻辑判断
wx:if --- wx:elif --- wx:else
<view><text wx:if="{{counter >= 90}}">优秀</text><text wx:elif='{{counter >= 60}}'>及格</text><text wx:else>不及格</text>
</view>
02 - hidden
hidden属性:
- hidden是所有的组件都默认拥有的属性
- 当hidden属性为true时, 组件会被隐藏
- 当hidden属性为false时, 组件会显示出来
hidden和wx:if的区别
hidden => 控制隐藏和显示是控制是否添加hidden属性,相当于display:none
wx:if => 是控制组件是否渲染的
03 - block
block : 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性
- 将需要进行遍历或者判断的内容进行包裹
- 将遍历和判断的属性放在block便签中,不影响普通属性的阅读,提高代码的可读性
04 - 列表渲染
wx:for
index : 遍历后在wxml中可以使用一个变量index,保存的是当前遍历数据的下标值
item : 数组中对应某项的数据
<!-- 遍历一个数组 => a,b,c -->
<view wx:for="{{['a','b','c']}}"wx:key="*this">{{item}} --- {{index}}</view><!-- 遍历一个字符串 => p,o,i,p,o,i -->
<view wx:for="{{'poipoi'}}"wx:key="item">{{item}} --- {{index}}</view><!-- 遍历数字 => 0 - 9 -->
<view wx:for="{{10}}"wx:key="*this">{{item}} --- {{index}}</view>
item - index
wx:for-item = ' ' => item 重命名
wx:for-index = ' ' => index 重命名
<view wx:for="{{['a','b','c']}}"wx:for-item='str'wx:for-index='key'wx:key="*this">{{str}} --- {{key}}</view>
key
使用wx:for时,可以添加一个key来提供性能
wx:key 的值以两种形式提供 :
- 字符串 => 代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能 动态改变
- 保留关键字 *this => 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字
3. Wxs
01 - 概念
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构
为什么要设计WXS语言
- 在WXML中是不能直接调用Page/Component中定义的函数的 ( 底层没有进行封装 )
- 但是某些情况, 我们可以希望使用函数来处理WXML中的数据(类似于Vue中的过滤器),这个时候就使用WXS了
WXS使用的限制和特点 :
- WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行
- WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序 提供的API
- 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备 上二者运行效率 无差异
- 最好使用ES6之前的语法,否则可能会有问题
02 - 写法
WXS有两种写法 :写在标签中 || 写在以.wxs结尾的文件中
WXS标签的属性 :
wxs :
- 每一个 .wxs 文件和 标签都是一个单独的模块
- 每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见
- 一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现
写法一 : 直接写在标签内
<!-- 1. 定义wxs标签,设定模块名 -->
<wxs module="format">// 2. 定义函数function priceFormat(price) {return price + '元'}// 3. 导出 : 必须导出后,才能被使用,且必须被CommonJs导出module.exports = {priceFormat: priceFormat}
</wxs><!-- 4. 使用 : 使用模块名.函数 => 进行使用 -->
<view wx:for="{{['111','222','333']}}"wx:for-item='money'wx:for-index='key'wx:key="*this">{{format.priceFormat(money)}}</view>
<!-- 5. 输出 : 111元、222元、333元 -->
写法二 : 独立的文件,通过src引入
定义format.wxs
// 1. 定义函数
function priceFormat(price) {return price + '元'
}
// 2. 导出 : 必须导出后,才能被使用,且必须被CommonJs导出
module.exports = {priceFormat: priceFormat
}
wxml
<!-- 3. 定义wxs标签,设定模块名,引入wxs文件 -->
<wxs module="format" src='./format.wxs' /><!-- 4. 使用 : 使用模块名.函数 => 进行使用 -->
<view wx:for="{{['111','222','333']}}"wx:for-item='money'wx:for-index='key'wx:key="*this">{{format.priceFormat(money)}}</view>
<!-- 5. 输出 : 111元、222元、333元 -->
八、小程序的事件处理
1. 组件事件类型
某些组件会有自己特性的事件类型
input : bindinput || bindblur || bindfocus
scroll-view : bindscrolltowpper || bindscrolltolower
2. 事件对象event
当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中
01 - currentTarget && target
target : 触发事件的元素
currentTarget : 处理事件的元素(大部分情况使用target)
wxml
<view id="outer" class="outer" bindtap="outerClick"><view id="inner" class="inner"></view>
</view>
wxss
.outer {width: 400rpx;height: 400rpx;background-color: #0f0;display: flex;justify-content: center;align-items: center;margin: 100rpx auto;
}.inner {width: 150rpx;height: 150rpx;background-color: #00f;
}
js
Page({outerClick(e) {console.log(e);// target : 触发事件的元素 => 点击的是蓝色,所以 target === innerconsole.log('target:', e.target);// currentTarget : 处理事件的元素 => 冒泡到外层了,所以 currentTarget === outerconsole.log('currentTarget:', e.currentTarget);}
})
02 - touches && changedTouches
touches : 当前屏幕上有多少个手指
changedTouches : 较上一个状态,改变了多少个手指
区别一 : touchend中不同
区别二 : 多手指触摸时不同
03 - 事件参数的传递
方式一 : 使用data-*
方式二 : 使用mark ( 2.7.1版本以上 ) => 事件 | 微信开放文档
data- : 需要区分currnetTarget 和 target,一般使用currnetTarget即可
mark : 会自动合并所有的mark数据,不受影响
wxml
<view id="outer"class="outer"bindtap="outerClick"data-name='coder'data-age='18'mark:address='地球🌍'><text mark:know='是的'>传递</text>
</view>
js
Page({outerClick(e) {// 通过data- : 传递过来的数据const { name, age } = e.currentTarget.datasetconsole.log(name, age);// 通过mark : 传递过来的数据,子组件和父组件mark数据会合并console.log(e.mark); // { know: "是的", address: "地球🌍" }const { address } = e.markconsole.log(address);}
})
04 - 事件参数的传递的例子
wxml
<view class="nav"><block wx:for="{{dataList}}"wx:key="*this"><view class="item"bindtap="itemClick"data-index='{{index}}'><text class="text {{currentIndex === index ? 'active' : '' }}">{{item}}</text></view></block>
</view>
wxss
.nav {display: flex;align-items: center;height: 100rpx;
}.item {flex: 1;text-align: center;
}.text {display: inline-block;padding-bottom: 10rpx;border-bottom: 6rpx solid #fff;
}.active {border-bottom-color: orange;
}
js
Page({data: {dataList: ['衣服👔', '裤子👖', '鞋子🥿'],currentIndex: 0},itemClick(e) {// 注意,这个时候使用currentTarget,才能拿到传递过来的参数// 如果不这么做,那么点到文字上就不会进行切换const { index } = e.currentTarget.datasetthis.setData({currentIndex: index})}
})
效果
3. 事件冒泡 && 事件捕获
事件捕获 : 从外到内
事件冒泡 : 从内到外
总是先捕获,再冒泡
- bind : 继续传递
- bind* => 冒泡监听到后继续传递
- capture-bind* => 捕获监听到后继续传递
- catch : 停止传递
- catch* => 冒泡监听到后即停止,不传递
- capture-catch* => 捕获到后即停止,不传递
4. 获取元素的宽高等
const query = wx.createSelectorQuery()
query.select('.swiper-item-layout').boundingClientRect()
query.exec((res) => {const winWid = wx.getSystemInfoSync().windowWidth // 获取当前屏幕的宽度const height = res[0].height // 获取元素的高度const width = res[0].width // 获取元素的宽度const swiperHeight = height / width * winWid + 'px' // 等比例设置值this.swiperHeight = swiperHeight
})
九、小程序的组件化开发
1. 概念
小程序刚刚推出时,是不支持组建化的,1.6.3版本后开始支持
组件化思想的应用 :
- 尽可能的将页面拆分成一个个小的、可复用的组件
- 让代码更加方便组织和管理,并且扩展性也更强
2. 创建并使用组件
01 - 创建
02 - 配置
需要在 json 文件中进行自定义组件声明
将component 字段设为 true 可这一组文件设为自定义组件
03 - 引入组件
局部注册组件
在页面的json文件中,配置usingComponents,即可在页面中使用
全局注册组件
在app.json的usingComponents声明某个组件,那么所有页面和组件可以直接使用该组件
04 - 使用组件
<view><!-- 使用即可 --><main-list />
</view>
05 - 注意事项
- 自定义组件也是可以引用自定义组件
- 使用usingComponents 字段
- 自定义组件和页面所在项目根目录名 不能以“wx-”为前缀
- 否则会报错
3. 组件的样式细节
01 - 组件内的样式 对 外部样式 的影响
组件内的class样式 : 只对组件wxml内的节点生效, 对于引用组件的Page页面不生效
ps : 组件内不能使用id选择器、属性选择器、标签选择器 => 因为会作用到外面,不安全
02 - 外部的样式 对 组件内样式 的影响
外部使用class的样式 : 只对外部wxml的class生效,对组件内是不生效的
ps :外部使用了id选择器、属性选择器不会对组件内产生影响
外部使用了标签选择器,会对组件内产生影响
03 - 如何让class可以相互影响
在Component对象中,可以传入一个options属性
其中options属性中有一个styleIsolation(隔离)属性
styleIsolation有三个取值 :
- isolated(默认取值,取隔离即可)
- 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响
- apply-shared
- 表示页面的样式将影响到自定义组件,但自定义组件中的样式不会影响页面
- shared
- 表示页面的样式将影响到自定义组件,自定义组件的样式也会影响页面和其他设置
- ......
// pages/logs/components/mainList.js
Component({options: {// 1. 默认值,相互不影响// styleIsolation: "isolated",// 2. 页面可以影响组件内部,组件内部不能影响页面// styleIsolation: "apply-shared",// 3. 相互都能影响styleIsolation: "shared",}
})
4. 组件的通信
01 - 向组件传递数据 - properties
可以使用 properties 属性
- 支持的类型
- String、Number、Boolean、Object、Array、null(不限制类型)
- 默认值
- 通过value设置默认值
页面定义
<view><!-- 使用组件 --><main-list title='我要飞的更高!!!' />
</view>
组件接收
// pages/logs/components/mainList.js
Component({properties: {// 传递过来的数据title: {type: "String",value: '我是默认的'}}
})
02 - 向组件传递样式 - externalClasses
说实话,有点繁琐,咕噜咕噜~
页面定义
页面传递
组件接收
组件使用
03 - 组件向外传递事件
组件定义
组件传递
页面监听
页面处理
04 - 页面直接调用组件方法
可在父组件里调用 this.selectComponent ,获取子组件的实例对象
调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")
ps : 如果有多个,可以使用 this.selectAllComponents
组件定义
// pages/logs/components/mainList.js
Component({data: {dataList: ['衣服👔', '裤子👖', '鞋子🥿'],currentIndex: 0},// 绑定的方法methods: {itemClick(e) {const { index } = e.currentTarget.datasetthis.setData({currentIndex: index})this.triggerEvent('itemClick', index)},// 定义一个方法textFun() {console.log('我是组件的方法!');}}
})
页面定义
<view><!-- 使用组件,定义一个选择器,这里用class --><main-list class="main-list-ref"bind:itemClick='itemClick' />
</view>
页面使用
Page({itemClick(params) {const { detail: index } = paramsconsole.log(index);},onShow() {// 1. 获取自定义组件实例,通过类选择器const mainListRef = this.selectComponent('.main-list-ref')// 2. 调用自定义组件方法mainListRef.textFun()// 3. 获取自定义组件数据console.log(mainListRef.data.dataList); // ["衣服👔", "裤子👖", "鞋子🥿"]}
})
5. 组件的插槽
小程序的插槽不支持默认值
01 - 单个插槽
组件
<view class="box"><view class="header">header</view><view class="content"><!-- 定义插槽 --><!-- 注 : 当没有传进来东西时,这里不会显示 --><slot></slot></view><view class="footer">footer</view>
</view>
页面
<view><!-- 使用组件时,在标签中间写的内容会传递到slot中 --><main-list>123</main-list><main-list><!-- 使用组件时,在标签中间写的内容会传递到slot中 --><button>a</button></main-list><main-list><!-- 使用组件时,在标签中间写的内容会传递到slot中 --><text>冲啊!</text></main-list></view>
效果
02 - 具名插槽
组件定义
<view class="box"><view class="left"><!-- 插槽名称为left --><slot name='left'></slot></view><view class="center"><!-- 插槽名称为center --><slot name='center'></slot></view><view class="right"><!-- 插槽名称为right --><slot name='right'></slot></view>
</view>
组件配置
// pages/logs/components/mainList.js
Component({options: {// 开启使用多个插槽 => 具名插槽multipleSlots: true}
})
页面使用
<view><main-list><!-- 使用左侧的插槽 --><view slot='left'>A</view></main-list><main-list><!-- 使用中间的插槽 --><view slot='center'>B</view></main-list><main-list><!-- 使用右边的插槽 --><text slot='right'>冲啊!</text></main-list>
</view>
03 - 解决默认值问题
小程序的插槽不支持默认值 => 可以用css的empty伪类 + 兄弟选择器来解决
组件
<view class="box"><view class="header">header</view><view class="content"><!-- 注 : 当没有传进来东西时,这里不会显示 --><slot></slot></view><!-- 当插槽无内容时,默认显示 --><view class="default">哈哈哈哈,我是默认</view><view class="footer">footer</view>
</view>
样式
/* 默认 隐藏默认值 */
.default {display: none;
}/* 当插槽为空时,显示 => 运用empty伪类 + 兄弟选择器 */
.content:empty+.default {display: block;
}
6. 组件中的混入 - behaviors
behaviors 是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins”
- 每个 behavior 可以包含一组属性、数据、生命周期函数和方法
- 组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用
- 每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior
01 - 共享的代码
// 创建一个Behavior并导出
export const counterBehaviors = Behavior({// 定义数据data: {count: 10},// 接收参数properties: {},// 引入其他behaviorsbehaviors: [],// 定义方法methods: {text() {console.log('text');}}
})
02 - 组件中使用
// 1. 倒入behaviors
import { counterBehaviors } from '../../../behaviors/counter'Component({// 2. 组件使用behaviorsbehaviors: [counterBehaviors]
})
7. 组件的生命周期
01 - 概念
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发
ps : 最重要的生命周期是 created attached detached
组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)
Component({// 生命周期写在这里面lifetimes: {// 组件实例被创建,可以用来进行网络请求created() {console.log('created');},// 组件实例进入页面节点树中attached() {console.log('attached');},// 组件渲染布局完成后ready() {console.log('ready');},// 组件被移除时detached() {console.log('detached');}}
})
02 - 组件所在页面的生命周期
一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理
组件所在页面的生命周期 => 在 pageLifetimes 定义段中定义
Component({// 组件生命周期lifetimes: {created() {console.log('created'); // 1},attached() {console.log('attached'); // 2},ready() {console.log('ready'); // 4},detached() {console.log('detached');}},// 组件所在页面的生命周期pageLifetimes: {show() {console.log('show', '组件所在页面被展示时执行'); // 3},hide() {console.log('hide', '组件所在页面被隐藏时执行');},resize(e) {console.log('resize', '组件所在页面尺寸变化时执行', e);}}
})
8. 组件Component构造器总结图
十、小程序系统API调用
1. 网络请求
微信提供了专属的API接口,用于网络请求: wx.request(Object object)
网址 : RequestTask | 微信开放文档
01 - API参数
02 - API使用
Page({data: {dataList: []},onLoad() {wx.request({// 请求地址url: 'https://www.baidu.com/',// 不管是post还是get,请求参数都是放到data中的data: {age: 18},// 请求成功的回调success: (res) => {const data = res.data.dataconsole.log(data);this.setData({dataList: data})},// 请求失败的回调fail: (err) => {console.log(err);}})}
})
03 - API封装
封装成函数
封装
export function request(option) {return new Promise((resolve, reject) => {wx.request({...option,success: (res) => {resolve(res.data)},fail: reject})})
}
使用
// 1. 导入
import { homeDataList } from '../../service/request/home/index'Page({data: {dataList: []},async onLoad() {const params = {url: 'https://www.baidu.com/',data: {age: 18}}// 2. 直接使用homeDataList(params).then(res => {console.log('res', res);}).catch(err => {console.log('err', err);})// 3. 使用async/awaitconst dataList = await homeDataList(params)console.log(dataList);}
})
封装成类
封装
class request {// 设置baseUrlconstructor(baseUrl) {this.baseUrl = baseUrl}// 封装 request 方法request(option) {const { url } = optionreturn new Promise((resolve, reject) => {wx.request({...option,// 拼接地址url: this.baseUrl + url,success: (res) => {resolve(res.data)},fail: reject})})}// 封装 get 方法get(option) {return this.request({ ...option, method: 'GET' })}// 封装 post 方法post(option) {return this.request({ ...option, method: 'POST' })}
}// 可创建多个实例,请求不同的地址
export const starRequest = new request('https://www.baidu.com')
使用
04 - 网络请求域名配置
每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信
小程序登录后台 – 开发管理 – 开发设置 – 服务器域名
配置时需要注意 :
- 域名只支持 https
- wx.request、wx.uploadFile、wx.downloadFile 和 wss (wx.connectSocket) 协议
- 域名不能使用 IP 地址
- 小程序的局域网 IP 除外 或 localhost
- 端口
- 配置端口
- 如 https://myserver.com:8080,但是配置后只能向 https://myserver.com:8080 发起请求。如果向https://myserver.com、https://myserver.com:9091 等 URL 请求则会失败
- 不配置端口
- 如 https://myserver.com,那么请求的 URL 中也不能包含端口,甚至是默认的 443 端口也不可以。如果向 https://myserver.com:443 请求则会失败
- 配置端口
- 域名必须经过 ICP 备案
- 不支持配置父域名,使用子域名
2. 展示弹窗效果
01 - showToast
showToast 和 showLoading 只能同时显示一个
效果
代码
wx.showToast({// 提示内容title: 'title',// 图标 => none error loading successicon: 'success',// 自定义图标 => 自定义图标的本地路径,image 的优先级高于 iconimage: '/assets/images/tabbar/cart_active.png',// 持续时间duration: 2000,// 是否显示透明蒙层,显示期间不能进行交互mask: true,// 成功回调success: (res) => {console.log('展示成功', res);},// 失败回调fail: (err) => {console.log('展示失败', err);},// 接口调用结束的回调函数(调用成功、失败都会执行)complete: (data) => {console.log('展示', data);}
})
02 - showLoading
和 showToast => icon为loadind,展示的效果相同
但是可以手动控制关闭弹窗的时间
效果
代码
wx.showLoading({// 提示内容title: '加载中',// 是否显示透明蒙层,显示期间不能进行交互mask: true,// 成功回调success: (res) => {console.log('展示成功', res);},// 失败回调fail: (err) => {console.log('展示失败', err);},// 接口调用结束的回调函数(调用成功、失败都会执行)complete: (data) => {console.log('展示', data);}
})// 两秒后,关闭弹窗 => 可在请求数据完成后,再调用该方法
setTimeout(function () {wx.hideLoading()
}, 2000)
03 - showModal
效果
代码
wx.showModal({// 提示的标题title: '你有钱吗',// 提示的内容content: '我有',// 是否显示取消按钮showCancel: true,// 取消按钮的文字,最多 4 个字符cancelText: '骗你哒',// 取消按钮的文字颜色,必须是 16 进制格式的颜色字符串cancelColor: '#f0f',// 确认按钮的文字,最多 4 个字符confirmText: '真的啦',// 确认按钮的文字颜色,必须是 16 进制格式的颜色字符串confirmColor: '#00f',// 是否显示输入框// editable: true,// 显示输入框时的提示文本// placeholderText: '我是提示内容',// 成功回调success: (res) => {/*** content => editable 为 true 时,用户输入的文本* confirm => 为 true 时,表示用户点击了确定按钮* cancel => 为 true 时,表示用户点击了取消*/if (res.confirm) {console.log('用户点击确定')} else if (res.cancel) {console.log('用户点击取消')}},// 失败回调fail: (err) => {console.log('展示失败', err);},// 接口调用结束的回调函数(调用成功、失败都会执行)complete: (data) => {console.log('展示', data);}
})
04 - showActionSheet
效果
代码
wx.showActionSheet({// 警示文案alertText: '你有钱吗',// 按钮的文字数组,数组长度最大为 6itemList: ['吃饭', '喝水', '打豆豆', '睡觉'],// 按钮的文字颜色itemColor: '#0f0',// 成功回调success: (res) => {/*** tapIndex => 用户点击的按钮序号,从上到下的顺序,从0开始*/console.log('展示成功', res, res.tapIndex);},// 失败回调,监听取消fail: (err) => {console.log('展示失败', err);},// 接口调用结束的回调函数(调用成功、失败都会执行)complete: (data) => {console.log('展示', data);}
})
3. 分享功能 onShareAppMessage
分享是小程序扩散的一种重要方式,小程序中有两种分享方式,通过 onShareAppMessage
此事件处理函数需要 return 一个 Object,用于自定义转发内容
方式一
点击右上角的菜单按钮,之后点击转发
直接配置 onShareAppMessage 方法即可
Page({onShareAppMessage() {return {title: '我是标题', // 分享后显示的标题path: '/pages/logs/logs', // 分享后打开的路径,别人打开的页面的路径imageUrl: '/assets/images/tabbar/cart_active.png' // 分享后显示的图片}}
})
方式二
监听用户点击页面内转发按钮 => button 组件 open-type="share"
页面设置后,再配置 onShareAppMessage 方法即可
// wxml
<view><button open-type="share">分享</button>
</view>// js
Page({onShareAppMessage() {return {title: '我是标题', // 分享后显示的标题path: '/pages/logs/logs', // 分享后打开的路径,别人打开的页面的路径imageUrl: '/assets/images/tabbar/cart_active.png' // 分享后显示的图片}}
})
4. 获取设备信息 wx.getSystemInfo
获取当前设备的信息,用于手机信息或者进行一些适配工作
wx.getSystemInfo(Object object)
Page({onShow() {wx.getSystemInfo({success: (res) => {console.log('success', res);},fail: (err) => {console.log('fail', err);},complete: (res) => {console.log('complete', res);},})}
})
5. 获取位置信息 wx.getLocation
对于用户的关键信息,比如获取用户的位置信息,需要获取用户的授权后才能获得
01 - 授权
在app.json中进行配置
地址 : 全局配置 | 微信开放文档
{"pages": ["pages/index/index"],// 配置权限"permission": {// 配置位置权限"scope.userLocation": {// 弹出框中显示的内容"desc": "我需要你的位置信息,马上给我"}},"window": {},"tabBar": {},"style": "v2","sitemapLocation": "sitemap.json"
}
02 - 获取
Page({onShow() {wx.getLocation({type: 'wgs84', // wgs84 返回 gps 坐标altitude: false,// 传入 true 会返回高度信息,但是会减慢接口返回速度isHighAccuracy: true, // 开启高精度定位highAccuracyExpireTime: 5000,// 高精度定位超时时间(ms),指定时间内返回最高精度,该值3000ms以上高精度定位才有效果// 接口调用成功的回调函数success: (res) => {/*** latitude => 纬度,范围为 -90~90,负数表示南纬* longitude => 经度,范围为 -180~180,负数表示西经* speed => 速度,单位 m/s,看当前设备是否在移动* accuracy => 位置的精确度,反应与真实位置之间的接近程度,可以理解成10即与真实位置相差10m,越小越精确* altitude => 高度,单位 m* verticalAccuracy => 垂直精度,单位 m(Android 无法获取,返回 0)* horizontalAccuracy => 水平精度,单位 m*/console.log('success', res);},// 接口调用失败的回调函数fail: (err) => {console.log('fail', err);},// 接口调用结束的回调函数(调用成功、失败都会执行)complete: (res) => {console.log('complete', res);},})}
})
6. Storage存储
01 - 同步
存储的代码执行完后,才会继续往后执行
也就是说,下一行代码就能获取到存储的值
Page({onShow() {// 存wx.setStorageSync('name', 'coder')wx.setStorageSync('age', 18)wx.setStorageSync('array', [1, 2, 3, 4])wx.setStorageSync('Object', { friends: '小明' })// 取console.log(wx.getStorageSync('name')); // coder// 删wx.removeStorageSync('name')// 清空wx.clearStorageSync()}
})
02 - 异步
不影响其他代码执行 => 存储后,不能立马获取到值
Page({onShow() {// 存wx.setStorage({key: 'name',data: "coder",encrypt: true, // 2.21.3 => 若开启加密存储,setStorage 和 getStorage 需要同时声明 encrypt 的值为 truesuccess: ({ errMsg }) => {console.log(errMsg); // setStorage:ok}})// 取wx.getStorage({key: 'name',encrypt: true, // 2.21.3 => 若开启加密存储,setStorage 和 getStorage 需要同时声明 encrypt 的值为 truesuccess: ({ errMsg, data }) => {console.log(errMsg, data); // getStorage:ok => coder}});// 删wx.removeStorage({key: 'name',success: ({ errMsg }) => {console.log(errMsg); // removeStorage:ok}})// 清空wx.clearStorage({success: ({ errMsg }) => {console.log(errMsg); // clearStorage:ok}})}
})
十一、页面跳转
1. 通过wx的API跳转
00 - switchTab - 跳转到 tabBar 页面
跳转到 tabBar 页面
并关闭其他所有非 tabBar 页面,使用 navigateBack 无法退回
// 跳转页面
wx.switchTab({url: '/pages/text/text',success: (res) => { console.log('success', res); },fail: (err) => { console.log('fail', err); },complete: (res) => { console.log('complete', res); },
})
01 - navigateTo - 普通页面跳转
保留当前页面,跳转到应用内的某个页面
但是不能跳到 tabbar 页面
// index页面
Page({// 监听方法handleClick() {const name = 'coder'const age = 19// 跳转页面wx.navigateTo({// 地址 ?后面为携带的参数url: `/pages/jump1/jump1?name=${name}&age=${age}`,})}
})// ---------------------------------------------------------------------------// pages/jump1/jump1.js
Page({// 接受从index页面跳转过来时接受到的参数onLoad(option) {console.log(option); // {name: "coder", age: "18"}}
})
02 - navigateBack - 页面返回
wx.navigateBack(Object object) => 关闭当前页面,返回上一页面或多级页面
Page({onShow() {setTimeout(() => {// 页面返回wx.navigateBack({// 默认返回上一页,可以设定delta: 1})}, 3000);}
})
03 - 页面跳转 - 数据传递(一)
在界面跳转过程中需要相互传递一些数据
首页 => 详情页
使用URL中的query字段
// index
Page({handleClick() {const name = 'coder'const age = 19// 跳转页面wx.navigateTo({url: `/pages/jump1/jump1?name=${name}&age=${age}`,})}
})
详情页 => 首页
在详情页内部拿到首页的页面对象,直接修改数据
// jump1页面
Page({onShow() {setTimeout(() => {// 页面返回wx.navigateBack({// 默认返回上一页,可以设定delta: 1})}, 3000);},// 拿到传递过来的数据onLoad(option) {console.log(option);},/*** 写在这里的理由 : 用户可能点击顶部状态栏中的返回键,写在这不管怎么返回,都会触发*/// 页面被注销时调用onUnload() {// 1. 获取到已经存在的所有页面const pages = getCurrentPages()// 2. 拿到上一个页面的实例 当前页面为最后一个,所以上一个页面是减2const prePage = pages[pages.length - 2]// 3. 直接设置值prePage.setData({ message: 'ccc' })}
})
04 - 页面跳转 - 数据传递(二)
在小程序基础库 2.7.3 开始支持events参数,也可以用于数据的传递
首页 => 详情页
使用URL中的query字段进行传递,定义events对象
// index页面
Page({// 监听方法handleClick() {const name = 'coder'const age = 19// 跳转页面wx.navigateTo({url: `/pages/jump1/jump1?name=${name}&age=${age}`,// 使用该参数events: {// 设置方法名 => 在子组件中调用该方法,传递数据过来acceptData(data) {console.log('acceptData', data); // {name:'coder'}},// 设置方法名acceptOtherData(data) {console.log('acceptOtherData', data); // {age:18}}}})}
})
详情页 => 首页
使用eventChanner,传递数据到上一个页面
// jump1页面
Page({onShow() {setTimeout(() => {// 页面返回wx.navigateBack({// 默认返回上一页,可以设定delta: 1})}, 3000);},// 拿到传递过来的数据onLoad(option) {console.log(option);},/*** 写在这里的理由 : 用户可能点击顶部状态栏中的返回键,写在这不管怎么返回,都会触发*/// 页面被注销时调用onUnload() {// 1. 拿到eventChanner渠道const eventChanner = this.getOpenerEventChannel()// 2. 通过渠道,拿到回调函数,并且传递数据给上一个页面eventChanner.emit('acceptData', {name: 'coder'})eventChanner.emit('acceptOtherData', {age: 18})}
})
2. 通过navigator组件
navigator组件主要就是用于界面的跳转的,也可以跳转到其他小程序中
01 - 跳转到 tabBar 页面
<navigator open-type="switchTab" url="/pages/logs/logs">跳转</navigator>
02 - 跳转到 普通 页面
<navigator url="/pages/jump1/jump1?name=123">跳转</navigator>
03 - 返回 上一个 页面
<navigator open-type="navigateBack" delta="1">跳转</navigator>
十二、小程序登录解析
1. 概念
01 - openid
openid : 当 在小程序 用微信功能登录时,每个微信都具备唯一标识openid
可把 openid 保存到数据库中,即使用户更换了手机,也能通过 openid 识别为同一用户
02 - unionid
unionid : 在微信的不同产品之间可用来识别是否为同一用户
小程序的 openid 和 公众号的 openid,可能是不一样的,但是unionid一样
03 - 用户身份多平台共享
再开一个页面或窗口 => 进行账号绑定 || 手机号绑定
openid - unionid - 手机号 => 就建立了联系
2. 登录流程
3. 代码
登录操作
可以写到 app.js 的 onLaunch 中
也可以写到 页面.js 的 onLoad 中
Page({/*** onLoad登录操作*/onLoad() {// 1. 判断token是否有值const token = wx.getStorageSync('token') || ''// 2. 判断token是否过期// ......// 有值 且 没过期if (token && '没过期') {// 做其他操作} else {// 3. 获取codethis.requestCode()}},// 登录获取coderequestCode() {wx.login({success: ({ code }) => {// 4. 将code发给后端this.requestBack(code)},})},// 将code发给后端requestBack(code) {console.log(code);wx.request({url: 'https://www.baidu.com',data: { code },method: 'POST',success: (res) => {// 5. 拿到身份标识( 自定义登录态 ),可能不会返回openid, unionid,看后端const { openid, unionid, token } = res.data// 6. 把 自定义登录态 存入storagewx.setStorageSync('token', token)},})}
})
十三、代码上传到Gitee
git操作都是大同小异,详细的可以看我之前写的git文章
网址 : 版本控制工具 之 Git_玄鱼殇的博客
1. 创建远程仓库
2. 配置远程仓库
01 - 本地点击版本管理
02 - 添加远程仓库
03 - 设置用户名和邮箱
04 - 设置网络和认证
3. 推送代码到远程仓库
01 - 首次推送
02 - 修改后推送
推送到本地仓库
拉取远程仓库代码
推送到远程仓库
相关文章:
微信小程序 之 原生开发
目录 一、前期预备 1. 预备知识 2. 注册账号 - 申请AppID 3. 下载小程序开发工具 4. 小程序项目结构 5. 小程序的MVVM架构 二、创建小程序项目 1. 查看注册的appId 2. 创建项目 3. 新建页面 01 - 创建text页面文件夹 02 - 新建text的page 03 - 在app.json中配置 …...
常用vim命令和vim基本使用及Linux用户的管理,用户和组相关文件
常用vim命令和vim基本使用及Linux用户的管理,用户和组相关文件1. vim 的基本介绍和使用1.1 vim的三种模式1.2 常用vim命令【小白】1.3 Vim键盘图:2. Linux用户管理2.1 添加用户2.2 删除用户2.3 修改账号3. Linux系统用户组的管理4. 用户和组相关文件4.1 …...
阿里云服务器部署前后端分离项目
阿里云服务器部署 【若依】 前后端分离项目 文章目录一、域名解析二、服务器操作系统置空三、部署方式四、需安装环境配置五、Linux服务器安装相应内容(具体安装步骤)(一)安装JDK(3种方式)使用Yum安装&…...
内核经典数据结构list 剖析
前言:linux内核中有很多经典的数据结构,list(也称list_head)为其中之一,这些数据结构都是使用C语言实,并且定义和实现都在单独的头文件list.h中。可以随时拿出来使用。list.h的定义不同linux发行版本路径不同,我们可以在/usr/incl…...
华为OD机试 - 考优选核酸检测点(Python)| 真题+思路+考点+代码+岗位
优选核酸检测点 题目 张三要去外地出差,需要做核酸,需要在指定时间点前做完核酸, 请帮他找到满足条件的核酸检测点。 给出一组核酸检测点的距离和每个核酸检测点当前的人数给出张三要去做核酸的出发时间 出发时间是 10 分钟的倍数 同时给出张三做核酸的最晚结束时间题目中…...
在魔改PLUS-F5280开发板上使用合封qsp iflash
文章目录引言硬件调整软件调整总结引言 由于目前灵动官网暂未发布正式版的PLUS-F5280开发板,可以使用现有的PLUS-F5270 v1.2开发板(下文简称PLUS-F5270开发版)替换为MM32F5280微控制器芯片,改装为PLUS-F5280开发板。本文记录了使…...
uni-app 瀑布流
效果图 一、组件 components/u-myWaterfall.vue <template><view class"u-waterfall"><view id"u-left-column" class"u-column"><slot name"left" :leftList"leftList"></slot></view&…...
华为OD机试 - 去除多余空格(Python)| 真题+思路+考点+代码+岗位
去除多余空格 题目 去除文本多余空格,但不去除配对单引号之间的多余空格。给出关键词的起始和结束下标,去除多余空格后刷新关键词的起始和结束下标。 条件约束: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oQABYuJD-1676475739950)(https://…...
MyBatis 二级缓存简单使用步骤
1、二级缓存使用 在 MyBatis 中默认二级缓存是不开启的,如果要使用需手动开启。在 mybatis-config.xml 配置文件中设置 cacheEnabled true ,配置如下: <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE c…...
kubeadmin kube-apiserver Exited 始终起不来查因记录
kubeadmin kube-apiserver Exited 始终起不来查因记录 [rootk8s-master01 log]# crictl ps -a CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD b7af23a98302e …...
论文投稿指南——中文核心期刊推荐(工程材料学)
【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…...
【动态规划】背包问题题型及方法归纳
背包问题的种类 背包问题是在规定背包容量为j的前提下,每个物品对应的体积为v[i],价值为w[i],从物品0到物品i中选择物品放入背包中,找出符合某种要求的价值。 (1)背包问题种类 01背包:每种物…...
全球十大资质正规外汇期货平台排行榜(最新版汇总)
外汇期货简称为FxFut,是“Forex Futures”的缩写,是在集中形式的期货交易所内,交易双方通过公开叫价,以某种非本国货币买进或卖出另一种非本国货币,并签订一个在未来的某一日期根据协议价格交割标准数量外汇的合约。 …...
使用Paramiko时遇到的一些问题
目录 1.背景 2.问题合集 1)“bash: command not found” 2)Paramiko中正常的输入,却到了stderr,而stdout是空 3)命令实际是alias 1.背景 在自动化脚本中,使用了库Paramiko,远程SSH到后台服…...
数据预处理(无量纲化、缺失值、分类特征、连续特征)
文章目录1. 无量纲化1.1 sklearn.preprocessing.MinMaxScaler1.2 sklearn.preprocessing.StandardScaler2. 缺失值3. 分类型特征4. 连续型特征数据挖掘的五大流程包括:获取数据数据预处理特征工程建模上线 其中,数据预处理中常用的方法包括数据标准化和归…...
【C#基础】C# 运算符总结
序号系列文章2【C#基础】C# 基础语法解析3【C#基础】C# 数据类型总结4【C#基础】C# 变量和常量的使用文章目录前言运算符1,算术运算符2,布尔逻辑运算符3,位运算符4,关系运算符5,赋值运算符6,其他运算符7&am…...
存储性能软件加速库(SPDK)
存储性能软件加速库SPDK存储加速存储性能软件加速库(SPDK)SPDK NVMe驱动1.用户态驱动1)UIO2)VFIOIOMMU(I/O Memory Management Unit)3)用户态DMA4)大页(Hugepage…...
微服务(五)—— 服务注册中心Consul
一、引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency>二、配置yml文件 server:port: 8006spring:application:name: cloud-payment-con…...
冷冻电镜 - ChimeraX Density Map 密度图 操作
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/129055160 由冷冻电镜所生成的Volume,需要观察其内部结构,使用ChimeraX进行操作。 加载Volumes,例如my_volume.mrc 效果如下: 高斯滤波 在命令行(Co…...
Matlab 点云旋转之轴角式
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 三维空间中表示旋转的方法有很多种,轴角式是其中非常经典的一种表示方式。虽然欧拉角表示旋转的方法很是常用,但欧拉角存在着万向锁这个问题,因此轴角式旋转在旋转使用中更为合适。其原理也很是明了,如下所述:…...
2023美赛数学建模资料思路模型
美赛我们为大家准备了大量的资料,我们会在比赛期间给大家分析美题目和相关的思路 全文都是干货,大家仔细阅读,资料文末自取! 首先我们来看美赛23年题型的一个变化: 美赛23年题目变化: A题:连…...
Nginx配置HTTP强制跳转到HTTPS
https 访问我们的测试域名 https://www.xxx.com 站点,但是当我们直接在浏览器地址栏中直接输入 www.xxx.com 的时候却发现进入的是 http 协议的网站,这与我们的初衷不一致。由于浏览器默认访问域名使用的是80端口,而当我们使用SSL证书后&…...
从实现到原理,聊聊Java中的SPI动态扩展
原创:微信公众号 码农参上,欢迎分享,转载请保留出处。 八股文背多了,相信大家都听说过一个词,SPI扩展。 有的面试官就很喜欢问这个问题,SpringBoot的自动装配是如何实现的? 基本上,…...
3、MySQL字符集
1.MySQL字符集和校验规则 字符集:是一套符号和编码的规则校验规则:是对该套符号和编码的校验,定义字符的排序和比较规则,其中是否区分大小写,跟校验规则有关。2.查看字符集方法 netstat -lntup |grep 3306 tcp6 0 0 :::3306 :::* …...
大漠插件最新中文易语言模块7.2302
模块名称:大漠插件中文模块最新通用7.2302模块简介:大漠插件中文模块最新通用7.2302模块特色:原翻译:花老板完善命令备注:易生易世本人花费一个月时间才将命令完善了插件的备注说明.且用且珍惜去掉了大漠插件定制版类.因为没用.模块特色:什么是中文模块?大漠插件模块是由大漠类…...
极客大挑战 2021
题量很大,收获挺多,持续时间也长,据说结束之后会再持续一段时间,然后题目会开源。 WEB Dark 暗网签到,难以置信 Welcome2021 改个请求方法会提示你文件,再进去就好了 babysql 直接把请求包扔sqlmap里&…...
C#开发的OpenRA加载文件的管理
C#开发的OpenRA加载文件的管理 在前面我们分析了mod.yaml文件,发现里面有很多文件列表, 比如下像下面的文件: Packages: ~^SupportDir|Content/cnc ~^SupportDir|Content/cnc/movies ^EngineDir $cnc: cnc ^EngineDir|mods/common: common ~speech.mix ~conquer.mix ~sounds…...
SSM实现文件上传
目录 SSM实现文件上传 1、修改from表单请求方式改为post,添加属性 2、修改springmvc配置文件,添加一下配置 3、后端方法 SSM实现文件上传 1、修改from表单请求方式改为post,添加属性: enctype"multipart/form-data"…...
OPENCV计算机视觉开发实践-图像的基本概念
1.图像与图形: 图像->客观世界的反映,图与像之结合 图->物体透射光与反射光的分布 像->人的视觉得对图的认识 图像->通过照相,摄像,扫描产生. 图形->通过数学规则产生,或者具有一定规则的图案.用一组符号或线条表示性质. 2.数字图像: 数字图像->称数码图像或…...
Android 9.0 ResolverActivity.java多个app选择界面去掉始终保留仅有一次
1.前言 在9.0的系统rom定制化开发过程中,在系统中安装同类型多个app的时候,在系统启动的过程中,会在启动launcher或播放器的过程中,在启动的过程中都是弹出选择框的,然后在选择启动哪个app,这些选择都是在ResolverActivity.java中完成的,所以需要在ResolverActivity.java…...
标题翻译为英文wordpress/开一个免费网站
optimizer_index_caching调整基于成本的优化程序的假定值, 即在缓冲区高速缓存中期望用于嵌套循环联接的索引块的百分比。它将影响使用索引的嵌套循环联接的成本。将该参数设置为一个较高的值,可以使嵌套循环联接相对于优化程序来说成本更低。 索引在缓冲区中出现的机率(百分比…...
苏州新区网站制作/seo和sem的关系
### MVC![](http://p0zfk1qh0.bkt.clouddn.com/markdownmvc.png) 视图(View):用户界面。 控制器(Controller):业务逻辑 模型(Model):数据保存 ** View 传送指令到 Contro…...
做宠物服务的相关网站/网站制作公司高端
我们阅读博客的时候经常会用到这样功能,当然有时候也会想把自己的网站上也加入类似的分享功能,各大厂商已经给出了相应的API,点击一个按钮即可弹出窗口进入分享,我们事先可以设置一些参数,一般常用的就是 网站的网址&a…...
成都做网站设/杭州seo中心
抽象类:对类的抽象,抽象其行为特征,分为数据抽象,即类的属性,过程抽象,即类的行为特征。抽象层次:是类的属性、行为抽象,全局进行抽象。是一种自下而上的设计。描述的是一继承关系&a…...
国外开源网站建设软件/seo服务商技术好的公司
这两天在捣鼓ListView widget,为了在ListView中加入Button这类的有 “点击” 事件的widget,请教了不少高手,感谢LandMark对我的认真讲解,下面把解决过程描述一下。ListView 和 其它能触发点击事件的widget无法一起正常工作的原因是…...
wordpress 当前位置/快速网站搭建
如何制作更改计算机名的脚本(有图)首先新建一个txt文档,输入以下代码echo offset /p newcomputername请输入新的计算机名:wmic computersystem where "name%computername%" call rename %newcomputername%以上代码输入后将文档另存为rename.ba…...