使用微信小程序 官方文档
一、微信小程序项目结构主要有四个文件类型
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。内部主要是微信自己定义的一套组件
WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式
js 逻辑处理,网络请求
json 小程序设置,如页面注册,页面标题及tabBar
二、主要文件
app.json 必须要有这个文件,如果没有这个文件,项目无法运行,因为微信框架把这个作为配置文件入口,整个小程序的全局配置。包括页面注册,网络设置,以及小程序的 window 背景色,配置导航条样式,配置默认标题
app.js 必须要有这个文件,没有也是会报错!但是这个文件创建一下就行 什么都不需要写以后我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量
app.wxss 可选
1.小程序的双向绑定和vue哪里不一样?
小程序直接 this.data 的属性是不可以同步到视图的,必须调用:
微信小程序在初始化之后,再对原来的数据对象进行任何更改,都始终不会生效!只能手动调用setData接口明确指明同步哪些键/值至视图层才会触发更新 vue则是对数据对象进行了监听,只要有更改就可以并且会立即触发视图层的更新
this.setData({
// 这里设置
})
2.小程序的 wxss 和 css 有哪些不一样的地方?
- 尺寸单位 rpx
rpx 是响应式像素,可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx。如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素
- 使用 @import 标识符来导入外联样式。@import 后跟需要导入的外联样式表的相对路径,用;表示语句结束
/** index.wxss **/
@import './base.wxss';
.container{
color: red;
}
3.小程序页面间有哪些传递数据的方法
- 使用全局变量实现数据传递
在 app.js 文件中定义全局变量 globalData, 将需要存储的信息存放在里面,使用getApp()方法拿到存储的信息
// app.js
App({
// 全局变量
globalData: {
userInfo: null
}
})
onLoad: function() {
const app = getApp();
// 获取全局变量
const userInfo = app.globalData.userInfo;
// 更新页面数据
this.setData({ userInfo: userInfo });
},
4.小程序的生命周期函数
onLoad(): 页面加载时触发。一个页面只会调用一次,可以在 onl oad 的参数中获取打开当前页面路径中的参数,建议在此调接口
onShow(): 页面显示/切入前台时触发,不建议在此调接口
onReady(): 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互
onHide() :页面隐藏/切入后台时触发。 如 navigateTo 或底部 tab 切换到其他页面,小程序切入后台等
onUnload() :页面卸载时触发。如 redirectTo 或 navigateBack 到其他页面时
注册页面 使用 Page 构造器注册页面
对于小程序中的每个页面,都需要在页面对应的 js
文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。
代码示例:
//index.js
Page({
data: {
text: "This is page data."
},
onl oad: function(options) {
// 页面创建时执行
},
onShow: function() {
// 页面出现在前台时执行
},
onReady: function() {
// 页面首次渲染完毕时执行
},
onHide: function() {
// 页面从前台变为后台时执行
},
onUnload: function() {
// 页面销毁时执行
},
onPullDownRefresh: function() {
// 触发下拉刷新时执行
},
onReachBottom: function() {
// 页面触底时执行
},
onShareAppMessage: function () {
// 页面被用户分享时执行
},
onPageScroll: function() {
// 页面滚动时执行
},
onResize: function() {
// 页面尺寸变化时执行
},
onTabItemTap(item) {
// tab 点击时执行
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// 事件响应函数
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
// 自由数据
customData: {
hi: 'MINA'
}
})
详细的参数含义和使用请参考 Page 参考文档
在页面中使用 behaviors
基础库 2.9.2 开始支持,低版本需做兼容处理。
页面可以引用 behaviors 。 behaviors 可以用来让多个页面有相同的数据字段和方法。
// my-behavior.js
module.exports = Behavior({
data: {
sharedText: 'This is a piece of data shared between pages.'
},
methods: {
sharedMethod: function() {
this.data.sharedText === 'This is a piece of data shared between pages.'
}
}
})
// page-a.js
var myBehavior = require('./my-behavior.js')
Page({
behaviors: [myBehavior],
onl oad: function() {
this.data.sharedText === 'This is a piece of data shared between pages.'
}
})
具体用法参见 behaviors 。
使用 Component 构造器构造页面
基础库 1.6.3 开始支持,低版本需做兼容处理。
Page
构造器适用于简单的页面。但对于复杂的页面, Page
构造器可能并不好用。
此时,可以使用 Component
构造器来构造页面。 Component
构造器的主要区别是:方法需要放在 methods: { }
里面。
代码示例:
Component({
data: {
text: "This is page data."
},
methods: {
onl oad: function(options) {
// 页面创建时执行
},
onPullDownRefresh: function() {
// 下拉刷新时执行
},
// 事件响应函数
viewTap: function() {
// ...
}
}
})
具体细节请阅读 Component 构造器
5.常用的页面事件处理函数
1. onPullDownRefresh()
监听用户下拉刷新事件。
- 需要在
app.json
的window选项中或页面配置中开启enablePullDownRefresh
。 - 可以通过wx.startPullDownRefresh触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
- 当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。
2.onReachBottom()
监听用户上拉触底事件。
3.onPageScroll(Object object)
监听用户滑动页面事件。
属性 | 类型 | 说明 |
scrollTop | Number | 页面在垂直方向已滚动的距离(单位px) |
注意:请只在需要的时候才在 page 中定义此方法,不要定义空方法。以减少不必要的事件派发对渲染层-逻辑层通信的影响。 注意:请避免在 onPageScroll 中过于频繁的执行 setData
等引起逻辑层-渲染层通信的操作。尤其是每次传输大量数据,会影响通信耗时。
4.onShareAppMessage(Object object)
监听用户点击页面内转发按钮(button 组件 open-type="share"
)或右上角菜单“转发”按钮的行为,并自定义转发内容。
注意:只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮
参数 | 类型 | 说明 | 最低版本 |
from | String | 转发事件来源。button :页面内转发按钮;menu :右上角转发菜单 | 1.2.4 |
target | Object | 如果 from 值是 button ,则 target 是触发这次转发事件的 button ,否则为 undefined | 1.2.4 |
webViewUrl | String | 页面中包含web-view组件时,返回当前web-view的url | 1.2.4 |
此事件处理函数需要 return 一个 Object,用于自定义转发内容,返回内容如下:
自定义转发内容 基础库 2.8.1 起,分享图支持云图片。
字段 | 说明 | 默认值 | 最低版本 |
title | 转发标题 | 当前小程序名称 | |
path | 转发路径 | 当前页面 path ,必须是以 / 开头的完整路径 | |
imageUrl | 自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持PNG及JPG。显示图片长宽比是 5:4。 | 使用默认截图 | 1.5.0 |
promise | 如果该参数存在,则以 resolve 结果为准,如果三秒内不 resolve,分享会使用上面传入的默认参数 | 2.12.0 |
示例代码
Page({
onShareAppMessage() {
const promise = new Promise(resolve => {
setTimeout(() => {
resolve({
title: '自定义转发标题'
})
}, 2000)
})
return {
title: '自定义转发标题',
path: '/page/user?id=123',
promise
}
}
})
6.onResize(Object object)
页面尺寸改变时触发。
响应显示区域变化
显示区域尺寸
显示区域指小程序界面中可以自由布局展示的区域。在默认情况下,小程序显示区域的尺寸自页面初始化起就不会发生变化。但以下三种方式都可以改变这一默认行为。
1.在手机上启用屏幕旋转支持
从小程序基础库版本 2.4.0 开始,小程序在手机上支持屏幕旋转。使小程序中的页面支持屏幕旋转的方法是:在 app.json
的 window
段中设置 "pageOrientation": "auto"
,或在页面 json 文件中配置 "pageOrientation": "auto"
。
代码示例:
{
"pageOrientation": "auto"
}
如果页面添加了上述声明,则在屏幕旋转时,这个页面将随之旋转,显示区域尺寸也会随着屏幕旋转而变化。
从小程序基础库版本 2.5.0 开始, pageOrientation
还可以被设置为 landscape
,表示固定为横屏显示
2.在 iPad 上启用屏幕旋转支持
从小程序基础库版本 2.3.0 开始,在 iPad 上运行的小程序可以支持屏幕旋转。使小程序支持 iPad 屏幕旋转的方法是:在 app.json
中添加 "resizable": true
。
{
"resizable": true
}
如果小程序添加了上述声明,则在屏幕旋转时,小程序将随之旋转,显示区域尺寸也会随着屏幕旋转而变化。注意:在 iPad 上不能单独配置某个页面是否支持屏幕旋转。
3.启用大屏模式
从小程序基础库版本 2.21.3 开始,在 Windows、Mac、车机、安卓 WMPF 等大屏设备上运行的小程序可以支持大屏模式。可参考小程序大屏适配指南。方法是:在 app.json
中添加 "resizable": true
代码示例:
{
"resizable": true
}
7.onTabItemTap(Object object)
基础库 1.9.0 开始支持,低版本需做兼容处理。
点击 tab 时触发
Object 参数说明:
参数 | 类型 | 说明 | 最低版本 |
index | String | 被点击tabItem的序号,从0开始 | 1.9.0 |
pagePath | String | 被点击tabItem的页面路径 | 1.9.0 |
text | String | 被点击tabItem的按钮文字 | 1.9.0 |
示例代码:
Page({
onTabItemTap(item) {
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
}
})
8.onSaveExitState()
基础库 2.7.4 开始支持,低版本需做兼容处理。
每当小程序可能被销毁之前,页面回调函数 onSaveExitState
会被调用,可以进行退出状态的保存。
9.组件事件处理函数
Page
中还可以定义组件事件处理函数。在渲染层的组件中加入事件绑定,当事件被触发时,就会执行 Page 中定义的事件处理函数。
示例代码:
<view bindtap="viewTap"> click me </view>
Page({
viewTap: function() {
console.log('view tap')
}
})
10.Page.route
基础库 1.2.0 开始支持,低版本需做兼容处理。
到当前页面的路径,类型为String
。
Page({
onShow: function() {
console.log(this.route)
}
})
三、封装微信小程序的数据请求
// 官方例子
wx.request({
url: 'test.php', //仅为示例,并非真实的接口地址
data: {
x: '' ,
y: ''
},
header: {
'content-type': 'application/json' // 默认值
},
success: function(res) {
console.log(res.data)
}
})
const baseUrl = 'https://api.it120.cc';
const http = ({ url = '', param = {}, ...other } = {}) => {
wx.showLoading({
title: '请求中,请耐心等待..'
});
let timeStart = Date.now();
return new Promise((resolve, reject) => {
wx.request({
url: getUrl(url),
data: param,
header: {
'content-type': 'application/json' // 默认值 ,另一种是 "content-type": "application/x-www-form-urlencoded"
},
...other,
complete: (res) => {
wx.hideLoading();
console.log(`耗时${Date.now() - timeStart}`);
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data)
} else {
reject(res)
}
}
})
})
}
const getUrl = (url) => {
if (url.indexOf('://') == -1) {
url = baseUrl + url;
}
return url
}
// get方法
const _get = (url, param = {}) => {
return http({
url,
param
})
}
const _post = (url, param = {}) => {
return http({
url,
param,
method: 'post'
})
}
const _put = (url, param = {}) => {
return http({
url,
param,
method: 'put'
})
}
const _delete = (url, param = {}) => {
return http({
url,
param,
method: 'put'
})
}
module.exports = {
baseUrl,
_get,
_post,
_put,
_delete
}
使用案例
const api = require('../../utils/api.js')
// 单个请求
api.get('list').then(res => {
console.log(res)
}).catch(e => {
console.log(e)
})
// 一个页面多个请求
Promise.all([
api.get('list'),
api.get(`detail/${id}`)
]).then(result => {
console.log(result)
}).catch(e => {
console.log(e)
})
四、登陆问题
代码如下:
//app.js
App({
onLaunch: function () {
console.log('App onLaunch');
var that = this;
// 获取商城名称
wx.request({
url: 'https://api.it120.cc/'+ that.globalData.subDomain +'/config/get-value',
data: {
key: 'mallName'
},
success: function(res) {
wx.setStorageSync('mallName', res.data.data.value);
}
})
this.login();
this.getUserInfo();
},
login : function () {
var that = this;
var token = that.globalData.token;
// 如果有token
if (token) {
// 检查token是否有效
wx.request({
url: 'https://api.it120.cc/' + that.globalData.subDomain + '/user/check-token',
data: {
token: token
},
success: function (res) {
// 如果token失效了
if (res.data.code != 0) {
that.globalData.token = null;
that.login(); // 重新登陆
}
}
})
return;
}
// 【1】调用微信自带登陆
wx.login({
success: function (res) {
// 【2】 拿到code去访问我们的后台换取其他信息
wx.request({
url: 'https://api.it120.cc/'+ that.globalData.subDomain +'/user/wxapp/login',
data: {
code: res.code
},
success: function(res) {
// 如果说这个code失效的
if (res.data.code == 10000) {
// 去注册
that.registerUser();
return;
}
// 如果返回失败了
if (res.data.code != 0) {
// 登录错误
wx.hideLoading();
// 提示无法登陆
wx.showModal({
title: '提示',
content: '无法登录,请重试',
showCancel:false
})
return;
}
// 【3】 如果成功后设置token到本地
that.globalData.token = res.data.data.token;
// 保存用户信息
wx.setStorage({
key: 'token',
data: res.data.data.token
})
}
})
}
})
},
// 注册?? [这个看需求]
registerUser: function () {
var that = this;
wx.login({
success: function (res) {
var code = res.code; // 微信登录接口返回的 code 参数,下面注册接口需要用到
wx.getUserInfo({
success: function (res) {
var iv = res.iv;
var encryptedData = res.encryptedData;
// 下面开始调用注册接口
wx.request({
url: 'https://api.it120.cc/' + that.globalData.subDomain +'/user/wxapp/register/complex',
data: {code:code,encryptedData:encryptedData,iv:iv}, // 设置请求的 参数
success: (res) =>{
wx.hideLoading();
that.login();
}
})
}
})
}
})
},
// 获取用户信息
getUserInfo:function() {
wx.getUserInfo({
success:(data) =>{
this.globalData.userInfo = data.userInfo;
wx.setStorage({
key: 'userInfo',
data: data.userInfo
})
return this.globalData.userInfo;
}
})
},
globalData:{
userInfo:null,
subDomain:"34vu54u7vuiuvc546d",
token: null
}
})
授权问题
getUserInfo: function () {
// 先调用wx.getSetting 获取用户权限设置
wx.getSetting({
success(res) {
console.log('1');
if (!res.authSetting['scope.userInfo']) {
wx.authorize({
scope: 'scope.userInfo',
success() {
// 用户已经同意小程序使用录音功能,后续调用 wx.getUserInfo接口不会弹窗询问
wx.getUserInfo({
success: (data) => {
this.globalData.userInfo = data.userInfo;
wx.setStorage({
key: 'userInfo',
data: data.userInfo
})
return this.globalData.userInfo;
}
})
}
})
} else {
console.log(2);
}
}
})
},
五、 微信小程序的优劣势
优势
- 即用即走,不用安装,省流量,省安装时间,不占用桌面
- 依托微信流量,天生推广传播优势
- 开发成本比 App 低
缺点
- 用户留存,即用即走是优势,也存在一些问题
- 入口相对传统 App 要深很多
- 限制较多,页面大小不能超过2M。不能打开超过10个层级的页面
六、如何实现下拉刷新、上拉加载
下拉刷新
- 首先在全局
config
中的window
配置enablePullDownRefresh
. - 在
Page
中定义onPullDownRefresh
钩子函数。到达下拉刷新条件后,该钩子函数执行,发起请求方法。 - 请求返回后,调用
wx.stopPullDownRefresh
停止下拉刷新。
config
config = {
pages: [
'pages/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#ccc',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: '#000',
enablePullDownRefresh: true
}
}
page
onPullDownRefresh() {
wepy.showNavigationBarLoading()
setTimeout(()=>{
this.getData = '数据拿到了'
wepy.stopPullDownRefresh()
wepy.hideNavigationBarLoading()
this.$apply()
},3000)
}
上拉加载
首先功能有
- 点击回到顶部 这个很好实现,有对应的回到顶部函数
- 滑动屏幕记录当前页数 这个也很好实现,主要是监听滚动事件,判断对应滚动条高度,去计算其与子容器的高度即可。
- 上拉加载动画
这里有两个实现的方案。一个是 page
自带的下拉触底钩子事件 onReachBottom
能做的只是下拉到底部的时候通知你触底了,一个是 scroll-view
标签自带事件。现在用两个方法分别实现一下上拉加载。
上拉触底事件 onReachBottom
<template>
<view class="loading"></view>
<view class="container"
@touchmove="moveFn"
@touchstart="startFn"
@touchend="endFn"
style="transform:translate3d(0,{{childTop}}px,0)">
<repeat for="{{list}}"
key="index"
index="index"
item="item">
<view>{{ item }}<text>{{index}}</text></view>
</repeat>
</view>
</template>
data = {
getData: '',
top: 0,
lastTop: 0,
canDrag: false,
list: []
}
onReachBottom() {
this.canDrag = true
}
methods = {
moveFn(ev) {
let nowY = ev.changedTouches[0].clientY
nowY = nowY-this.lastTop
if(nowY > 0 )
this.canDrag = false
if( nowY<=0 && this.canDrag ) {
this.top = nowY
}
if( -this.top>= this.maxTop )
this.top = -this.maxTop
},
startFn(ev) {
this.lastTop = ev.changedTouches[0].clientY
},
endFn() {
if(this.top <= -this.maxTop) {
this.text = "去请求数据了"
setTimeout(()=>{
this.text = "请求回来了"
this.canDrag = false
this.list.push(...["数据","数据","数据"])
this.$apply()
this.top = 0;
return
},1000)
}
},
gotoTop() {
wepy.pageScrollTo({
scrollTop: 0
})
}
}
滚动容器实现上拉加载
scroll-view: 可滚动视图区域。
<navigation-bar title="Weixin" back="{{false}}" color="black" background="#FFF"></navigation-bar>
<scroll-view class="scrollarea" scroll-y scroll-x type="list" style="height: 200px;" bindscroll="text1">
<!-- 一、scroll-view组件 -->
<view style="width: 200%;height: 800px; background-image: linear-gradient(to bottom right,red,yellow);">
</view>
</scroll-view>
Page({
text1:function(e){
console.log(e.detail);
}
})
第二种方式:
<scroll-view scroll-y
id="content"
@scroll="scroll"
@scrolltolower="lower"
scroll-top="{{gotoTopNum}}"
lower-threshold="100"
style="transform:translate3d(0,{{childTop}}px,0)">
<view class="sty-search"
@touchmove="moveContent"
@touchstart="startContent"
@touchend="endContent">...</view>
</scroll-view>
methods = {
async lower() {
this.canDrag = true
},
scroll (ev) {
this.scrollTop = ev.detail.scrollTop
if (ev.detail.deltaY > 0) {
this.canDrag = false
}
let nowSet = this.documentHeight+this.scrollTop-this.contentHeader
let num = Math.ceil(nowSet/this.listHeight) - 1
num = Math.floor(num / this.pageBean.pageSize) + 1
num = (num > this.pageBean.pageNo) ? this.pageBean.pageNo : num
if(num != this.page) {
this.page = num
this.$apply()
}
},
startContent(ev) {
this.lastTop = ev.changedTouches[0].clientY
if(!this.documentHeight){
this.documentHeight = wx.getSystemInfoSync().windowHeight
}
/* 这句是解决回到顶部的bug */
if (this.gotoTopNum || this.gotoTopNum==0) { this.gotoTopNum = undefined }
},
moveContent (ev) {
let {
pageNo,
pageSize,
totalCount
} = this.pageBean
let nowY = ev.changedTouches[0].clientY
nowY = nowY-this.lastTop
if (this.canDrag && nowY) {
this.state = 1;
if (nowY <= -this.maxMove) {
nowY = -this.maxMove
}
if (nowY <= 0) {
this.childTop = nowY
}
}
},
async endContent(ev) {
let {
pageNo,
pageSize,
totalCount
} = this.pageBean
if (this.childTop === -this.maxMove) {
/* 状态 */
if (pageNo >= this.maxPage || pageNo * pageSize >= totalCount) {
this.state = 0
} else {
this.pageBean.pageNo++
await this.fillData()
this.childTop = 0
this.canDrag = false
this.$apply()
}
}
/* 如果没超过刷新高度则重置 */
this.childTop = 0
},
gotoTop() {
this.gotoTopNum = 0
},
}
七、bindtap 和 catchtap 的区别是什么
相同点:首先他们都是作为点击事件函数,就是点击时触发。在这个作用上他们是一样的,可以不做区分
不同点:他们的不同点主要是bindtap是不会阻止冒泡事件的,catchtap是阻止冒泡的
八.简述微信支付的业务流程
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。参见统一下单API。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。api参见本章节app端开发步骤说明
步骤5:商户后台接收支付通知。api参见支付结果通知API
步骤6:商户后台查询支付结果。,api参见查询订单API(查单实现可参考:支付回调和查单实现指引) 详情参考这里
九、在小程序中又哪些方法让图片宽高比例保持不变?
一、使用mode:widthFix
widthFix:宽度不变,高度自动变化,保持原图宽高比不变。
首先我们先设置image的mode为widthFix,然后给图片加一个固定rpx的宽度,比如:730rpx。
这样图片也可以自适应了。。因为小程序的rpx本身就是一个自适应显示的单位
二、使用bindload绑定函数动态自适应。
我们可以给image绑定一个函数,这个函数,如上面的bindload说明一样,我们可以获取到原图的宽度和高度。
然后计算他们的宽高比率。。然后设置一个宽度大小(rpx),最后通过style动态设置image的宽高。代码如下:
html代码:
<image src="{{ item }}" bindload="imageLoad" data-index="{{ index }}"
style="width:{{ images[index].width }}rpx; height:{{ images[index].height }}rpx;"></image>
js代码:
Page({
data: {
images:{}
},
imageLoad: function(e) {
var $width=e.detail.width, //获取图片真实宽度
$height=e.detail.height,
ratio=$width/$height; //图片的真实宽高比例
var viewWidth=718, //设置图片显示宽度,左右留有16rpx边距
viewHeight=718/ratio; //计算的高度值
var image=this.data.images;
//将图片的datadata-index作为image对象的key,然后存储图片的宽高值
image[e.target.dataset.index]={
width:viewWidth,
height:viewHeight
}
this.setData({
images:image
})
}
})
10、小程序中的路由跳转switchTab navigateTo redirectTo的区别
wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
wx.switchTab():跳转到 abBar 页面,并关闭其他所有非 tabBar 页面
wx.navigateBack()关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层
wx.reLaunch():关闭所有页面,打开到应用内的某个页面
11、说说小程序中wx:if和hidden的区别
相同点:
wx:if 与 hidden 都用来控制小程序元素的显示
不同点:
wx:if:
- 1、条件为 true 时显示
- 2、当元素显示时渲染
- 3、元素变为不显示时销毁元素
hidden:
- 1、条件为 false 时显示
- 2、当元素显示时渲染
- 3、元素变为不显示时保留元素
- 4、相当于使用了dispaly
总结: 1、当元素频繁切换是否显示时使用 hidden ,因为 wx:if 会频繁地销毁渲染元素 2、当元素不频繁切换是否显示时使用 wx:if,因为 wx:if 会避免页面加载时渲染过多,导致页面加载缓慢
uniapp 面试题
1. 什么是 Uniapp?它有什么特点?
UniApp 是一个基于Vue的跨平台应用开发框架,可以使用 Vue.js 的开发语法编写一次代码,然后通过编译生成可以在多个平台(包括iOS、Android、H5 等)上运行的应用。UniApp 具有以下特点:
跨平台:开发者可以使用相同的代码基底构建多个平台的应用,避免了针对不同平台的重复开发。
高性能:UniApp 在运行时使用原生渲染技术,具有接近原生应用的性能表现。
开放生态:UniApp 支持原生插件和原生能力的扩展,可以调用设备的硬件功能和第三方原生 SDK。
开发便捷:UniApp 提供了丰富的组件和开发工具,简化了应用开发和调试的流程。
2. 请解释 UniApp 中的生命周期钩子函数及其执行顺序。
在 UniApp 中,每个页面和组件都有一系列的生命周期钩子函数,用于在特定的时机执行代码。以下是 UniApp 中常用的生命周期钩子函数及其执行顺序:
onLoad:页面/组件加载时触发。
onShow:页面/组件显示在前台时触发。
onReady:页面/组件初次渲染完成时触发。
onHide:页面/组件被隐藏在后台时触发。
onUnload:页面/组件被销毁时触发。
执行顺序为:onLoad -> onShow -> onReady -> onHide -> onUnload。
3. 请解释 UniApp 中的条件编译是如何工作的.
答案:UniApp 中的条件编译允许开发者根据不同的平台或条件编译指令来编写不同的代码。在编译过程中,指定的平台或条件将会被处理,并最终生成对应平台的可执行代码。条件编译通过在代码中使用 #ifdef、#ifndef、#endif 等指令进行控制。例如,可以使用 #ifdef H5 来编写只在 H5 平台生效的代码块。
4. 请解释 UniApp 中的跨平台兼容性问题和解决方案。
由于不同平台的差异,UniApp 在跨平台开发时可能会遇到一些兼容性问题。为了解决这些问题,可以采取以下几个方面的策略.
使用条件编译:根据不同的平台,编写对应平台的代码,使用条件编译指令来控制代码块的执行。
使用平台 API:UniApp 提供了一些平台 API,可以通过条件编译指令来使用特定平台的功能和能力。
样式适配:不同平台的样式表现可能有差异,使用 uni-app-plus 插件中的 upx2px 方法来进行样式适配,使得在不同平台上显示一致。
原生扩展:使用原生插件和扩展来调用设备的原生功能和第三方 SDK,以解决特定平台的需求。
5、uniApp中如何发送网络请求?
可以使用uni.request方法发送网络请求,通过设置url、method、data等参数来实现不同的请求,
代码如下:亦可自行封装
uni.request({
url: 'https://api.example.com/data',
method: 'GET',
success: (res) => {
console.log(res.data);
},
fail: (err) => {
console.error(err);
}
});
6、uniApp中如何进行数据缓存?
可以使用uni.setStorageSync方法进行数据缓存,将数据存储到本地缓存中。
// 存储数据到本地缓存
uni.setStorageSync('key', 'value');
// 从本地缓存中读取数据
const data = uni.getStorageSync('key');
console.log(data); // 输出:value
7.uniApp中如何实现下拉刷新和上拉加载更多?
可以使用uni.onPullDownRefresh方法实现下拉刷新,使用uni.onReachBottom方法实现上拉加载更多。
// 在页面的onPullDownRefresh方法中实现下拉刷新
onPullDownRefresh() {
// 执行刷新操作
console.log('下拉刷新');
// 刷新完成后调用uni.stopPullDownRefresh()方法停止刷新
uni.stopPullDownRefresh();
}
// 在页面的onReachBottom方法中实现上拉加载更多
onReachBottom() {
// 执行加载更多操作
console.log('上拉加载更多');
}
8、uniApp中如何获取用户地理位置信息?
可以使用uni.getLocation方法获取用户的地理位置信息。
uni.getLocation({
success: (res) => {
console.log(res.latitude, res.longitude);
},
fail: (err) => {
console.error(err);
}
});
9、uniApp中如何进行微信支付?
可以使用uni.requestPayment方法进行微信支付,通过设置支付参数来实现支付功能。
uni.requestPayment({
provider: 'wxpay',
timeStamp: '1234567890',
nonceStr: 'abcdefg',
package: 'prepay_id=1234567890',
signType: 'MD5',
paySign: 'abcdefg',
success: (res) => {
console.log(res);
},
fail: (err) => {
console.error(err);
}
});
10、uniApp中如何进行音频的播放和控制?
可以使用uni.createInnerAudioContext方法创建音频实例,通过调用实例的方法来实现音频的播放和控制
// 创建音频实例
const audio = uni.createInnerAudioContext();
// 设置音频资源
audio.src = 'http://example.com/audio.mp3';
// 播放音频
audio.play();
// 暂停音频
audio.pause();
// 停止音频
audio.stop();
11、uniApp中如何进行图片的懒加载?
可以使用uni.lazyLoadImage组件实现图片的懒加载,将图片的src属性设置为需要加载的图片地址
<template>
<view>
<uni-lazy-load-image src="http://example.com/image.jpg"></uni-lazy-load-image>
</view>
</template>
<script>
export default {
components: {
'uni-lazy-load-image': '@/components/uniLazyLoadImage.vue'
}
};
</script>
12、uniApp中如何获取设备信息?
可以使用uni.getSystemInfo方法获取设备信息,包括设备型号、操作系统版本等。
uni.getSystemInfo({
success: (res) => {
console.log(res.model, res.system);
},
fail: (err) => {
console.error(err);
}
});
13、uniApp中如何实现图片预览功能?
可以使用uni.previewImage方法实现图片预览功能,通过设置urls参数来指定要预览的图片地址。
uni.previewImage({
urls: ['http://example.com/image1.jpg', 'http://example.com/image2.jpg']
});
14、uniApp中如何实现页面的下拉刷新和上拉加载更多?
可以使用uni.onPullDownRefresh方法实现页面的下拉刷新,使用uni.onReachBottom方法实现页面的上拉加载更多
// 在页面的onPullDownRefresh方法中实现下拉刷新
onPullDownRefresh() {
// 执行刷新操作
console.log('下拉刷新');
// 刷新完成后调用uni.stopPullDownRefresh()方法停止刷新
uni.stopPullDownRefresh();
}
// 在页面的onReachBottom方法中实现上拉加载更多
onReachBottom() {
// 执行加载更多操作
console.log('上拉加载更多');
}
15、uniApp中如何实现页面的分享功能?
可以使用uni.showShareMenu方法开启页面的分享功能,使用uni.onShareAppMessage方法设置分享的标题、路径等。
示例代码:
// 开启页面的分享功能
uni.showShareMenu();
// 设置分享的标题、路径等
uni.onShareAppMessage(() => {
return {
title: '分享标题',
path: '/pages/index/index'
};
});
16、uniApp中如何实现页面的转发功能?
可以使用uni.share方法实现页面的转发功能,通过设置title、path等参数来指定转发的标题和路径。
uni.share({
title: '转发标题',
path: '/pages/index/index'
});
17、uniApp中如何实现页面的登录授权?
可以使用uni.login方法获取用户登录凭证,然后将凭证发送到后端进行验证,根据验证结果来判断用户是否登录。
// 获取用户登录凭证
uni.login({
success: (res) => {
const code = res.code;
// 将凭证发送到后端进行验证
uni.request({
url: 'https://api.example.com/login',
method: 'POST',
data: {
code: code
},
success: (res) => {
console.log(res.data);
// 根据验证结果来判断用户是否登录
if (res.data.success) {
console.log('用户已登录');
} else {
console.log('用户未登录');
}
},
fail: (err) => {
console.error(err);
}
});
},
fail: (err) => {
console.error(err);
}
});
18、Uniapp 应用的生命周期、页面的生命周期、组件的生命周期.
一、应用的生命周期
1.onLaunch——当uni-app 初始化完成时触发(全局只触发一次)
2.onShow——当 uni-app 启动,或从后台进入前台显示
3.onHide——当 uni-app 从前台进入后台
4.onError——当 uni-app 报错时触发
5.onUniNViewMessage——对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯
6.onUnhandledRejection——对未处理的 Promise 拒绝事件监听函数(2.8.1+)
7.onPageNotFound——页面不存在监听函数
8.onThemeChange——监听系统主题变化
二、页面的生命周期
1.onInit——监听页面初始化,其参数同 onl oad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onl oad
2.onLoad——监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例
3.onShow——监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
4.onReady——监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
5.onHide——监听页面隐藏
6.onUnload——监听页面卸载
7.onResize——监听窗口尺寸变化
三、组件的生命周期
uni-app 组件支持的生命周期,与vue标准组件的生命周期相同
1.beforeCreate——在实例初始化之后被调用。
2.created——在实例创建完成后被立即调用。
3.beforeMount——在挂载开始之前被调用。
4.mounted——挂载到实例上去之后调用。详见 注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用$nextTickVue官方文档
5.beforeUpdate——数据更新时调用,发生在虚拟 DOM 打补丁之前。
6.updated——由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
7.beforeDestroy——实例销毁之前调用。在这一步,实例仍然完全可用。
8.destroyed——Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。