发布时间:2022-12-21 文章分类:编程知识 投稿人:李佳 字号: 默认 | | 超大 打印

小程序开发整理

使用uni-app跨端开发框架,代码写法与vue2一致。

一、与web开发的区别

1. 运行方式不同

npm run dev:mp-weixin后,用微信开发者工具打开dist中工程。

2. 标签与web开发不同

标签的对应关系

小程序中使用 web中使用
view div
text span
image img
navigator
此外,uni-app 还提供scroll-viewswiper等内置组件。

3. 运行环境从浏览器变成v8引擎

不能使用documentwindowlocalstoragecookie等浏览器自带对象,但是可以使用 uni 提供的 api 替代。

3.1 获取dom元素

需要用到SelectorQuery 对象。

const query = uni.createSelectorQuery().in(this);
query.select('#id').boundingClientRect(data => {
  console.log("得到布局位置信息" + JSON.stringify(data));
  console.log("节点离页面顶部的距离为" + data.top);
}).exec();
// select 返回 NodesRef 对象,即为节点信息。

注:我们常用的ref获取dom,不能用在uni-app内置组件上,只能用在自定义组件上。

3.2 数据缓存

本地数据缓存

// 异步
uni.setStorage({key: '', data: '', success: ()=>{}, fail: ()=>{}, complete: ()=>{}})
uni.getStorage({key: '', success: ()=>{}, fail: ()=>{}, complete: ()=>{}})
uni.removeStorage({key: '', success: ()=>{}, fail: ()=>{}, complete: ()=>{}})
uni.clearStorage()
// 同步
uni.setStorageSync({key: '', data: ''})
uni.getStorageSync({key: ''})
uni.removeStorageSync({key: ''})
uni.clearStorageSync()
// 获取当前 storage 相关信息
uni.getStorageInfo({success: (keys, currentSize, limitSize)=>{}})
const {keys, currentSize, limitSize} = uni.getStorageInfoSync();

4. 工程目录的区别

projectName/src
    ├── components
    ├── pages
    ├── ...
    ├── pages.json                    
    └── manifest.json

4.1 新增 pages.json

pages.json 文件用来对 uni-app 进行全局配置,决定页面文件的路径、组件自动引入规则、分包加载配置、窗口样式、原生的导航栏、底部的原生tabbar 等。

1)组件自动引入规则

"easycom": {
    "^tp-(.*)": "@/tp-view-ui/components/tp-$1/tp-$1.vue"
},

通过uni-app的easycom,只要组件安装在项目的 components 目录下,并符合 components/组件名称/组件名称.vue 目录结构。就可以不用引用、注册,直接在页面中使用。

2)页面文件路径

编译后,pages的第一个路径会成为首页

"pages": [
    {
        "path": "pages/index/indexA",
        "style": {
            "navigationBarTitleText": "AAA",
            "backgroundColor": "#FFFFFF"
        }
    },
    {
        "path": "pages/index/indexB",
        "style": {
            "navigationBarTitleText": "BBB",
            "backgroundColor": "#FFFFFF"
        }
    }
],

3)小程序的分包加载机制

微信小程序每个分包的大小是2M,总体积一共不能超过20M。

在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,会把对应分包自动下载下来,下载完成后再进行展示。

"subPackages": [
    {
        "root": "pages/xxxA",
        "pages": [{
            "path": "list/list",
            "style": {}
        }]
    }, 
    {
        "root": "pages/xxxB",
        "pages": [{
            "path": "detail/detail",
            "style": {}
        }]
    }
],

4.2 新增 manifest.json

manifest.json 文件是应用的配置文件,用于指定应用的名称、图标、权限等。

"mp-weixin": {
    /* 微信小程序特有相关 */
    "appid": "wx303f35140da12d22",
    "setting": {
        "urlCheck": true, // 检查安全域名和 TLS 版本
        "minified": true, // 上传代码时自动压缩
        "postcss": true, // 上传代码时样式自动补全
        "es6": true // ES6 转 ES5
    },
    "usingComponents": true, // 全局自定义组件
    "permission": { // 小程序接口权限相关设置
        "scope.userLocation": {
            "desc": "你的位置信息将用于小程序位置接口的效果展示"
        }
    }
},

appid:微信小程序的AppID,登录 微信公众平台 申请。

5. CSS 注意事项

5.1 像素单位

uni-app 默认为 rpx。rpx 即响应式 px,一种根据屏幕宽度自适应的动态单位。

一般UI上手机模型宽度为375px,换算关系为 1px = 2rpx。

5.2 布局

推荐使用 flex 布局。

比如上下子元素高度不固定,中间子元素占据剩余空间:

小程序开发与web开发的区别及特殊功能实现

.flex {
    display: flex;
    flex-direction: column;
    height: 600px; /* 父元素一定要指定高度 */
    width: 375px;
}
.flex-box1 {
    height: 200px;
    background: #b7dff0;
}
.flex-box2 {
    background-color: #bfa;
    flex: auto;
}
.flex-box3 {
    height: 200px;
    background: #b7dff0;
}

5.3 小程序组件的视图层级

组件内元素被shadow-root包裹,修改样式时需要做/deep/穿透。

小程序开发与web开发的区别及特殊功能实现

二、uni-app 的生命周期

1. 应用生命周期

只能在App.vue里监听应用的生命周期

函数名 说明
onLaunch uni-app 初始化完成时触发(全局只触发一次)
onShow uni-app 启动,或从后台进入前台显示
onHide uni-app 从前台进入后台
onError uni-app 报错时触发
onUniNViewMessage nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯
onUnhandledRejection 对未处理的 Promise 拒绝事件监听函数(2.8.1+)
onPageNotFound 页面不存在监听函数
onThemeChange 监听系统主题变化

2. 页面生命周期

函数名 说明
onLoad 监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参)
onShow 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
onReady 监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
onHide 监听页面隐藏
onUnload 监听页面卸载
onResize 监听窗口尺寸变化
... ....

微信小程序的页面生命周期

小程序开发与web开发的区别及特殊功能实现

使用 onLoad 来页面传参

//在起始页面跳转到test.vue页面并传递参数
uni.navigateTo({
	url: 'test?id=1&name=uniapp'
});
// 在test.vue页面接受参数
export default {
	onLoad(option) { //option为object类型,会序列化上个页面传递的参数
		console.log(option.id); //打印出上个页面传递的参数。
		console.log(option.name); //打印出上个页面传递的参数。
	}
}
uni.navigateTo({
	url: 'test?data=' + JSON.stringify(obj)
});
onLoad: function (option) {
	const data = JSON.parse(option.data);
}
uni.navigateTo({
	url: 'test?data=' + encodeURIComponent(JSON.stringify(obj))
});
onLoad: function (option) {
	const data = JSON.parse(decodeURIComponent(option.data));
}

除了 onLoad,还可以用 vuexuni.$on(eventName,callback)uni.$emit(eventName,OBJECT)进行页面通讯。

3. 组件生命周期

与 vue 标准组件的生命周期相同

函数名 说明 平台差异说明
beforeCreate 在实例初始化之前被调用。
created 在实例创建完成后被立即调用。
beforeMount 在挂载开始之前被调用。
mounted 挂载到实例上去之后调用。
beforeUpdate 数据更新时调用,发生在虚拟 DOM 打补丁之前。 仅H5平台支持
updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。 仅H5平台支持
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

三、特点功能整理

1. 二维码显示

使用插件 tki-qrcode,uni-app 二维码生成器。

安装

npm i tki-qrcode -S

引入

import tkiQrcode from "tki-qrcode";
export default {
    components: {tkiQrcode}
}

使用

<tki-qrcode
            ref="qRCodeRef"
            :val="qrcodeUrl"
            :size="424"
            :onval="true"
            :loadMake="true"
            :showLoading="true"
            @result="getQrImgUrl" />

属性

属性名 类型 默认值 可选值 说明
size Number 200 生成的二维码大小
unit String upx px 大小单位尺寸
val String 二维码 要生成的内容
lv Number 3(一般不用设置) 容错级别
onval Boolean false 监听val值变化自动重新生成二维码
loadMake Boolean false 组件初始化完成后自动生成二维码,val需要有值
showLoading Boolean true false 是否显示loading
loadingText String 二维码生成中 loading文字
... ... ... ... ...

方法

方法名 参数 默认值 说明
_makeCode() 生成二维码
_clearCode() 清空二维码(清空二维码会触发result回调 返回值为空)
_saveCode() 保存二维码到图库

事件

事件名 返回值 说明
result 生成的图片base64或图片临时地址 返回二维码路径 注:_clearCode()后返回空

2. 二维码卡片下载

使用插件xWxmlToCanvas,根据微信小程序wxml-to-canvas封装。

安装

npm i x-wxml-to-canvas -S

引入

实测引入node_modules内插件,条件编译时会走H5,而不是MP(小程序)。只有复制到项目内,才会走小程序。

import xWxmlToCanvas from './components/x-wxml-to-canvas/x-wxml-to-canvas';
export default {
    components: {xWxmlToCanvas}
}

使用

<xWxmlToCanvas
               ref="xWxmlToCanvas" 
               :hide="true" 
               :useCORS="true" 
               :width="311" 
               :height="518" 
               :xStyle="myStyle" 
               :xWxml="myWxml">
</xWxmlToCanvas>

属性

字段 类型 默认值 描述
hide Boolean false canvas是否在页面可见 true 通过fixed将canvas移至屏幕外
width Number 300 canvas宽度,单位px
height Number 300 canvas高度,单位px
xWxml String wxml 模板
xStyle Object {} 样式
useCORS Boolean true canvas 图片跨域

wxml 模板

const wxml = (projectName, inviteToChainStore, inviteExpiredTime, imgUrl) => `
    <view class="invite-card vertical-center pos-r">
        <text class="fw-b project-name">${projectName}</text>
        <image class="qrcode" src="https://www.cnblogs.com/culciful/archive/2022/12/21/${imgUrl}"></image>
        <text class="invite-desc fw-b">${inviteToChainStore}</text>
        <view class="footer">
            <text class="expired-time ta-c text">${inviteExpiredTime}</text>
            <text class="text ta-c">TP-LINK商云</text>
        </view>
    </view>
`;

imgUrl 通过tki-qrcode组件获取。

样式

对象属性值为对应 wxml 标签的 class 驼峰形式。需为每个元素指定 width 和 height 属性,否则会导致布局错误。

存在多个 className 时,位置靠后的优先级更高,子元素会继承父级元素的可继承属性。

元素均为 flex 布局。left/top 等 仅在 absolute 定位下生效。

const style = (rowLength) => {
    let textWidth = 212;
    return {
        "verticalCenter": {
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            textAlign: 'center',
        },
        "inviteCard": {
            width: 311, // 单位为 px
            height: 518,
            position: 'relative',
            backgroundColor: '#fff',
            borderRadius: 16,
        },
        "projectName": {
            marginTop: 32,
            fontSize: 16,
            lineHeight: '1.2',
            height: rowLength * 22,
            width: textWidth,
            fontWeight: 600,
        },
 		...
    };
};

方法

方法名 描述 返回值
renderToCanvas 将wxml渲染至页面
canvasToTempFilePath 将canvas转为图片地址 (H5端 Canvas 内绘制的图像需要支持跨域访问才能成功) promise函数,返回 图片地址,h5为base64
getCanvasImage renderToCanvas 与 canvasToTempFilePath 合并 promise函数,返回 图片地址,h5为base64
saveImageToPhotosAlbum 图片保存至本地 promise函数,返回 true / flase
this.$refs.xWxmlToCanvas.renderToCanvas().then(() => {
    this.$refs.xWxmlToCanvas.canvasToTempFilePath().then(res => {
        this.$refs.xWxmlToCanvas.saveImageToPhotosAlbum(res);
    });
});

真机调试不支持canvas type2d,可用预览模式。

3. 退出页面时拦截显示弹窗

3.1 开启小程序页面返回询问对话框

watch: {
    isChanged:{
        handler: function(val) {
            //#ifdef MP-WEIXIN
            if (val) {
                wx.enableAlertBeforeUnload({ // 只有真机会出现
                    message: this.$t('pStoreInfo.quitConfirm')
                });
            } else {
                wx.disableAlertBeforeUnload();
            }
            //#endif
        },
        immediate: true
    }
}

样式简单时可以使用。

小程序开发与web开发的区别及特殊功能实现

3.2 微信小程序视图容器 page-container

“假页”容器组件,效果类似于 popup 弹出层,页面内存在该容器时,当用户进行返回操作,关闭该容器不关闭页面。

<tp-safe-view has-cutline class="u-h-full">
	<!--弹窗内容-->  	
    <page-container
        :show="show"
        position="center"
        @beforeleave="beforeleave">
       <!--页面主体内容-->
    </page-container>
</tp-safe-view>
beforeleave() {} // 离开前触发

四、其他事项记录