14、电脑相关、移动端基础(术语|长度单位|设备像素|倍图)、vant-ui相关、微信公众平台、微信小程序-目录说明|WXML语法|WXS语法|事件系统|组件|自定义组件|API、uniapp跨端框架-简介|教程|组件|全局文件、postcss.config.js(2750行)
附、电脑相关 (1)查看命令行:win+r; cmd; 确定 (2)查看电脑配置:win+r; msinfo32; 确定 (3)windows10系统输入法切换的快捷键设置步骤:至少有2种输入法同时备用 A、开始-齿轮-时间和语言-语言-中文(简体中国)-选项-(添加键盘-微软拼音-)微软拼音-选项-按键-模式切换 (4)搜狗输入法的快捷键界面:S图标-更多设置-属性设置-按键 A、中英切换 B、系统功能快捷键-系统功能快捷键设置 (5)广告屏保的位置与删除 A、重启 B、此电脑-(上方中间的)查看-显示-隐藏的项目 C、打开,C:\Users\制造商(NINGMEI)\AppData\Local\Temp D、删除该位置下的所有文件 (6)谷歌截全屏的步骤 A、F12 B、ctrl+shift+p C、输入full D、点击Capture full size screenshot 另,免费在线网页转图片,https://www.url2pic.com/url2pic/index.html (7)postcss-pxtorem,px转rem 一、移动端基础 1、移动端的常用术语 (1)Uni,统一的,读you ni (2)IDE,集成开发环境(Integrated Development Environment),如vscode (3)SDK,软件开发工具包(Software Development Kit),软件开发时,开发工具的集合,通常由编译器、调试器和应用编程接口组成 (4)uniCloud,基于serverless的云开发平台,为开发者提供免费服务器,由DCloud(数字天堂)、阿里云、腾讯云三者联合实现 2、移动端的长度单位(vw、vh、vmin、vmax、%、em、rem、dp、pt、rpx、dot、dpi、ppi、Retina) 附、px,通用长度单位,像素,pixel,/ˈpɪksl/ (1)通用 A、vw,viewpoint width,视窗宽度,1vw等于视窗宽度的1%,如width: calc(100vw - 260px);font-size: 5vw; B、vh,viewpoint height,视窗高度,1vh等于视窗高度的1%,如height: calc(100vh - 260px);font-size: 5vh; C、vmin,vw和vh中较小的那个,font-size: vw,文字在横、竖屏下,大小不一致 D、vmax,vw和vh中较大的那个,font-size: vmax,文字在横、竖屏下,大小一致 E、%,相对于父元素的尺寸 F、em,相对于父字体大小 G、rem,相对于根字体大小 (2)专用 A、dp,Android长度单位,'ppi/160'px;sp,Android字体大小单位 B、pt,IOS长度单位,'ppi/163'px;自然界的长度单位,1/72英寸,0.35毫米 C、rpx,微信长度单位,1rpx=1/750的屏宽 (3)其它 A、dot,点,印刷品的最小单位 B、dpi,点密度,每英寸屏幕所包含的点数,Dots per inch C、ppi,像素密度,每英寸屏幕所包含的像素数,Pixels per inch D、retina display技术,视网膜显示技术,就是像素密度大一些而已 iPhone6将一个像素点分拆为四个像素进行显示,像素密度提高4倍,达到326ppi,超过人眼能区分的最大像素密度300ppi //简单说就是,一个物理像素占位面积小一点,单位面积物理像素多一点;用pxtorem后,字体占位面积不变,但因包含像素多,因而更清晰=====文字、图片===== 附、rem,示例 <style> //根字体定义一 html { font-size: 20px; } //根字体定义二 :root { font-size: 20px; } </style> <script> //根字体定义三 var designWidth = 1000 ; document.documentElement.style.fontSize = document.documentElement.clientWidth/designWidth+"px"; //代码尺寸为1rem,对应设计稿尺寸为1px </script> //postcss.config.js里的相关配置 require('postcss-pxtorem')({//px转rem rootValue: 37.5, //对应设计图宽度375px propList: ['*'], //将哪些属性的px值转换 }) 3、物理像素比 (1)像素,显示屏图像或CSS图像的最小单位,单位是px,包含 A、物理像素 B、逻辑像素 (2)物理像素,也叫设备像素,显示屏的最小可控制单元 附、分辨率,纵横方向的物理像素点数 A、1K显示屏(分辨率,1920*1080) B、2K显示屏(分辨率,2560*1440) C、4K显示屏(分辨率,3840*2160) (3)逻辑像素,也叫CSS像素,CSS的最小可控制单元,正常情况下,1个物理像素显示1个逻辑像素 (4)物理像素比,也叫设备像素比(window.devicePixelRatio),物理像素/逻辑像素,含义是几个物理像素显示1个逻辑像素 A、公司4K、21.5寸屏幕,1个物理像素小,缩放设为200%,2个物理像素显示1个逻辑像素;媒体查询2k,左300,右970,中间剩余像素 B、住处4K、43.0寸屏幕,1个物理像素大,缩放设为100%,1个物理像素显示1个逻辑像素;媒体查询4k,左200,右485,中间剩余像素 C、综合分辨率、尺寸、缩放后,上面两者字体大小一样 D、console.log(window.devicePixelRatio) 4、倍图(是正常像素密度的几倍,就用几倍图) (1)正常情况下的对应关系 A、一倍图:设计稿1,宽度750*1px;分辨率1,x*y B、二倍图:设计稿2,宽度750*2px;分辨率2,2x*2y C、三倍图:设计稿3,宽度750*3px;分辨率3,3x*3y D、四倍图:设计稿4,宽度750*4px;分辨率4,4x*4y,如iPhone6,其物理像素比为1, (2)真实项目:一张设计稿3,适配分辨率1、分辨率2、分辨率3、的显示屏, A、处理方案1,给1种分辨率写1套代码,先判断屏幕分辨率,再导入代码 分辨率1显示屏的div宽高用设计稿尺寸的1/3,背景图片用设计稿原图片尺寸的100%填充 分辨率2显示屏的div宽高用设计稿尺寸的2/3,背景图片用设计稿原图片尺寸的100%填充 分辨率3显示屏的div宽高用设计稿尺寸的3/3,背景图片用设计稿原图片尺寸的100%填充 B、处理方案2,以px为单位,用postcss-pxtorem把px转换成rem,使各种分辨率,如安卓、IOS的屏幕,显示相同效果 div宽高用设计稿尺寸的1/3,背景图片用设计稿原图片尺寸的100%填充 附、代码,背景图片用设计稿原图片尺寸的100%填充,//=====文字、图片===== //下面,设计稿1的图片放在分辨率1的显示屏上,效果是1个逻辑像素被放到1个物理像素里显示;像素密度不变,正常显示 //下面,设计稿2的图片放在分辨率1的显示屏上,效果是4个逻辑像素被压缩到1个物理像素里显示;像素密度不变,正常显示 //下面,设计稿2的图片放在分辨率2的显示屏上,效果是1个逻辑像素被放到1个物理像素里显示;像素密度变大,高清显示 background-image: url(example@2x.png) no-repeat; background-size: 100% auto; 5、特别注意 (1)移动端项目 A、各个页面的跳转关系 B、数据临时存储与清除 C、静态数据的来源(设计稿或后台) (2)存储临时数据,以备后退时使用 A、确定时,用localStorage存储数据 B、后退时,用localStorage获取数据 C、提交后,用localStorage删除数据 D、也可以用vuex存储、获取、删除数据 (3)iPhone12pro max,跳到新网页,新网页的位置没到顶 A、原因:跳转前的网页没到顶,浏览器把前网页的位置用在后网页上 B、解决:document.body.scrollTop=0; document.documentElement.scrollTop=0; 二、vant-ui相关 1、<input type="value"> (1)button,定义可点击按钮(多数情况下,用于通过 JavaScript 启动脚本) (2)checkbox,定义复选框 (3)file,定义输入字段和 "浏览"按钮,供文件上传 (4)hidden,定义隐藏的输入字段,发送表单的时候,隐藏域的信息也被一起发送到服务器, https://blog.csdn.net/weixin_38098192/article/details/90265302 (5)image,定义图像形式的提交按钮 (6)password,定义密码字段,该字段中的字符被掩码 (7)radio,定义单选按钮 (8)reset,定义重置按钮,重置按钮会清除表单中的所有数据 (9)submit,定义提交按钮,提交按钮会把表单数据发送到服务器 (10)text,定义单行的输入字段,用户可在其中输入文本,默认宽度为20个字符 2、深度选择器 当<style scoped>只作用于当前组件中的元素,可采用下列方式影响到子组件 附、全局样式 <style> .wrap .child { color: red; } </style> (1)本页样式 >>> ,原生css支持,sass/less可能无法识别 <style scoped> .wrap >>> .child { color: red; } </style> (2)本页样式 /deep/ ,sass/less可识别,在vue 3.0会报错 <style scoped> .wrap /deep/ .child { color: red; } </style> (3)本页样式 ::v-deep ,vue 3.0支持,编译速度快 <style scoped> .wrap ::v-deep .child { color: red; } </style> 3、vant-ui动态内容 (1)notify 消息提示,没有遮罩,页面顶部显示,有样式变化,3秒后自动消失 (2)toast 轻提示,没有遮罩,页面居中显示,无样式变化,3秒后自动消失 (3)NoticeBar 通知栏,没有遮罩,固定位置显示,有样式变化,不消失 (4)Popover 气泡弹出框,没有遮罩,点击处显示,会基于reference插槽的内容进行定位,常用于下拉选项, (5)overlay 遮罩层,全屏罩住 (6)popup 弹出层,有遮罩,常用触底显示,确认后消失,常用于省市县、日期选择 (7)dialog 弹出框,有遮罩,常用居中显示,确认后消失 4、van-field (1)输入框,正常 (2)文本框,type="textarea" (3)下拉框的逻辑 输入框禁用,右侧添加三角, 点击事件让下方气泡popup出现、传出序号、计算-从总数据中找出的相关数据-成下拉选项, 点击事件从自身数据中找出的相关数据-成为下拉选项,气泡popup出现 点击确定时,给对应的v-model赋值,气泡消失 (4)其它,用input插槽, 自定义输入框,使用此插槽后,与输入框相关的属性和事件将失效 在Form组件进行表单校验时,会使用input插槽中子组件的value,而不是Field组件的value (5)<van-uploader/>的部分属性 capture,图片选取模式,可选值为camera,直接调起摄像头 after-read,文件读取完成后的回调函数 before-read,文件读取前的回调函数,返回false可终止文件读取,支持返回Promise 4、Rule数据结构,只有一个对象项的数组 (1)required,是否为必选字段,boolean (2)message,错误提示文案 (3)trigger,本项规则的触发时机,可选值为onChange、onBlur (4)formatter,格式化函数,将表单项的值转换后,再用“pattern”或“validator”进行校验 (5)pattern,通过正则表达式进行校验,返回值为false时,红色的message出现在输入框的下方 (6)validator,通过函数进行校验,返回值为false时,机制让红色的message出现在输入框的下方; 返回值为promise实例时,机制向其注入resolve、reject,在reject里让红色的message出现在输入框的下方 validator:function(rule, val, callback) { return new Promise(function(resolve, reject) { setTimeout(function() { const dataNum = Date.now() if (dataNum % 2 === 0) { resolve('成功') } else { reject('失败') } }, 2000) }) } 5、插槽input示例 (1)html部分 <van-form @submit="beforeSubmit" ref="form"> <template v-for="(item,idx) in formList"> <div class="sign-form" :key="idx" v-if="item.inputType == 0"> <van-field name="name" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" show-word-limit :label="item.topicName" v-model="formData[idx]" :placeholder="'请输入'+item.topicName" :maxlength="item.numLimit" /> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 1"> <van-field rows="4" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" autosize v-model="formData[idx]" :label="item.topicName" type="textarea" show-word-limit /> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 2"> <van-field :label="item.topicName" v-model="formData[idx]" right-icon="arrow-down" readonly placeholder="请选择" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" @click="changeCol(idx)" /> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 3 && item.isCheckbox == 0"> <van-field :label="item.topicName" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]"> <template #input> <van-radio-group v-model="formData[idx]" direction="horizontal" class="hor-style"> <van-radio v-for="(v,k) in JSON.parse(item.optionInfo)" :name="v.option" :key="k">{{v.option}}</van-radio> </van-radio-group> </template> </van-field> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 3 && item.isCheckbox == 1"> <van-field :label="item.topicName" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]"> <template #input> <van-checkbox-group v-model="formData[idx]" :max="item.selectLimitMax ? item.selectLimitMax : 0" direction="horizontal"> <van-checkbox v-for="(value,key) in JSON.parse(item.optionInfo)" :name="value.option" shape="square" :key="key">{{value.option}}</van-checkbox> </van-checkbox-group> </template> </van-field> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 4"> <div class="van-form_card"> <div class="field__label">{{item.topicName}}</div> <div class="field__desc">支持“图片”扩展名:png、gif、jpeg、pcx、psd、tiff</div> </div> <van-field name="name" type="hidden" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" v-model="formData[idx]"> <template #input> <div class="upload-preview"> <van-image v-if="formData[idx]" width="4rem" height="3rem" fit="contain" :src="formData[idx]" /> <van-uploader :before-read="uploadFile" accept="image/png,image/gif,image/jpeg,image/pcx,image/psd,image/tiff" :name="idx"> <van-icon name="plus" /> </van-uploader> </div> </template> </van-field> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 5"> <div class="van-form_card"> <div class="field__label">{{item.topicName}}</div> <div class="field__desc">支持“视频”扩展名:avi、MP4、rmvb</div> </div> <van-field name="name" type="hidden" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" v-model="formData[idx]"> <template #input> <div class="flex-col"> <div class="video-upload" v-if="showUpload"> <span>视频上传中...</span> <van-progress :show-pivot="false" :percentage="videoUploadPercent" /> </div> <span class="link" v-if="formData[idx]" @click="href(idx)">{{videoName[idx]}}</span> <van-uploader :before-read="uploadVideo" accept="*" v-if="!showUpload" :name="idx"> <van-button icon="plus" type="primary">上传视频</van-button> </van-uploader> </div> </template> </van-field> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 6"> <div class="van-form_card"> <div class="field__label">{{item.topicName}}</div> <div class="field__desc">支持“文件”扩展名:doc、docx、txt、pdf、pptx、ppt、xlsx、xls</div> </div> <van-field name="name" type="hidden" :rules="[{ validator: valiFormData, message: '请选择',index:idx }]" v-model="formData[idx]"> <template #input> <div class="flex-col"> <span class="link" v-if="formData[idx]" @click="href(idx)">{{formData[idx]}}</span> <van-uploader :before-read="uploadFile" accept=".doc, .docx, .txt, .pdf, .pptx, .ppt, .xlsx, .xls" :name="idx"> <van-button icon="plus" type="primary">上传文档</van-button> </van-uploader> </div> </template> </van-field> </div> <div class="sign-form" :key="idx" v-if="item.inputType == 7"> <van-field readonly @click="clickDatePicker(idx)" name="name" :rules="[{ validator: valiFormData, message: '请选择日期',index:idx }]" :label="item.topicName" v-model="formData[idx]" :placeholder="'请选择'+item.topicName" /> <van-popup v-model="showDatePicker" position="bottom"> <van-picker show-toolbar title="选择日期" :columns="dateCol" @cancel="showDatePicker = false" @confirm="dateConfirm" /> </van-popup> <!-- van-popup默认在兄级加蒙层van-overlay,若没有出现,可能有人在项目的全局给清除了 --> </div> </template> <div class="vt-foot "> <van-button :loading="loading" loading-text="保存中..." native-type="submit" block color="#fdb235">提交</van-button> <!-- native-type,原生button标签的type属性,表单内点击此按钮,自动触发表单的onsubmit事件 --> <!-- loading,设置按钮为加载状态,加载状态下默认会隐藏按钮文字 --> <!-- loading-text,设置加载状态下的文字 --> </div> </van-form> (2)js部分 A、上传图片 uploadFile(file, detail) { let formData = new FormData(); formData.append('file', file); axios.post(this.$upload, formData, { 'Content-Type': 'multipart/form-data' }) .then(res => { if (res.data && res.data.code === 10000) { this.formData[detail.name] = res.data.data; let temp = res.data.data; this.formData.splice(detail.name, 1, temp); } else { this.$dialog.alert({ title: '提示', message: '上传文件失败', theme: 'round-button', }) .then(() => { //on close }); } }) }, B、上传视频 来源,https://help.aliyun.com/document_detail/383952.html import OSS from "ali-oss"; //开放存储服务(OpenStorageService,简称OSS),是阿里云对外提供的海量,安全,低成本,高可靠的云存储服务。 //用户可以通过简单的API(REST方式的接口),在任何时间、任何地点、任何互联网设备上进行数据上传和下载。 <van-uploader accept="*" v-if="!showUpload" :name="idx" :before-read="uploadVideo"> <van-button icon="plus" type="primary">上传视频</van-button> </van-uploader> uploadVideo(file, detail) { let type = file.name.substring(file.name.lastIndexOf(".") + 1) .toLowerCase() if (this.videoType.indexOf(type) < 0 || file.type.indexOf("video") < 0) { this.$dialog.alert({ title: '提示', message: '仅支持 .avi, .mp4, .rmvb, .mov 格式的视频', theme: 'round-button', }); return; } let max = 1024 * 1024 * 1024; if (file.size > max) { this.$dialog.alert({ title: '提示', message: '上传视频大小不能超过 1G!', theme: 'round-button', }) .then(() => {}); return; } myRequest({ tokenName: "ios", }) .then(data => { let client = new OSS({ region: "oss-cn-beijing", accessKeyId: data.data.data.accessKeyId, accessKeySecret: data.data.data.accessKeySecret, bucket: data.data.data.bucketName, stsToken: data.data.data.securityToken, }); const suffix = file.name.substr(file.name.indexOf(".")); let fileUrl = `test/${new Date().getTime()}${suffix}`; client .multipartUpload(fileUrl, file, { progress: (p) => { this.videoUploadPercent = Math.round(p * 100); this.showUpload = true; }, partSize: 102400, }) .then((res) => { this.showUpload = false; this.videoName[detail.name] = res.name; let url = res.res.requestUrls[0]; this.formData[detail.name] = url.substring(0, url.indexOf("?")); let temp = this.formData[detail.name]; this.formData.splice(detail.name, 1, temp); }) .catch((err) => { this.showUpload = false; console.log(err); this.$dialog.alert({ title: '提示', message: '上传失败', theme: 'round-button', }) }); }) } 三、微信公众平台账号 附、简称 A、“微信账号”简称“微信号” B、“微信公众平台账号”简称“平台号” 1、重要网址 (1)开发 A、开发文档,https://developers.weixin.qq.com/miniprogram/dev/framework/ B、开发者工具,https://developers.weixin.qq.com/miniprogram/dev/devtools/devtools.html C、开通微信开发者.代码管理,https://developers.weixin.qq.com/miniprogram/dev/devtools/wechatvcs.html (2)注册、登录、git仓库 A、注册网址,https://mp.weixin.qq.com/ 微信十种产品,https://developers.weixin.qq.com/doc/ 四种微信公众号,https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN, 小程序发布流程,https://mp.weixin.qq.com/wxamp/home/guide?token=1509394140 B、登录网址,https://mp.weixin.qq.com/ 管理后台,https://mp.weixin.qq.com/wxamp/home/guide 开发版本,https://mp.weixin.qq.com/wxamp/wacodepage/getcodepage C、git仓库网址,https://git.weixin.qq.com/ 四种微信公众号的任意1种账号注册成功,都会生成该仓库网址,该仓库与微信号关联,不会随公众号注销而注销 2、四种微信公众号 附、四种微信公众号网址,https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN, (1)订阅号 (2)服务号 (3)小程序(微信小程序-后面详细介绍) (4)企业微信(原企业号) 3、微信公众号账号注册 附、注册网址,https://mp.weixin.qq.com/ (1)点击“立即注册” (2)点击“4种类型中的1种” (3)如果点击的是“小程序”,那么还需要在跳转后的页面点击“前往注册” (4)填写邮箱、密码、验证码、勾选同意、点击注册, A、每个邮箱仅能申请一个小程序==========非常重要=========== B、作为登录账号,请填写未被微信公众平台注册,未被微信开放平台注册,未被个人微信号绑定的邮箱 (5)点击登录邮箱、登录邮箱、点击邮箱里的链接 A、注册国家/地区:中国大陆;主体类型:个人; B、身份证姓名、身份证号码、管理员手机号码、短信验证码、管理员身份验证(微信扫一扫)、继续,其中微信扫一扫 把微信号与微信小程序号关联起来 1个微信号能关联5个公众号==========非常重要=========== C、请确认以下提交的主体信息、确定 D、信息提交成功,前往小程序(管理后台),见7 4、小程序账号注销 附、登录网址,https://mp.weixin.qq.com/ (1)登录小程序的管理员账号 (2)如果提示该账号已冻结,则根据提示进行解冻 (3)如果尚无AppID(小程序ID),则需要先进行“AppID生成” (4)管理后台-点击(左下方)“设置”-点击(页面中间)“账号信息”里的“账号注销”按钮,(微信号的)公众平台安全助手-收到注销信息 (5)0-6*24小时内,可以电脑登录,取消注销 (6)6*24--14*24小时之间,可以电脑登录,取消注销或确认注销,逾期不确认账号将恢复正常, (7)如果不取消注销或确认注销,那么从 7*24小时开始,每隔24小时,在-微信号的公众平台安全助手,都会收到注销确认信息,直到取消注销或确认注销或达到7次 (8)确认注销后,微信扫一扫登录,不再出现该账号 5、小程序账号的作用 (1)生成(小程序)管理后台 A、管理项目版本,管理开发者 B、1个小程序账号,其管理后台只能存储1个小程序项目的3个版本,供发布 (2)生成存储仓库 A、存储项目代码 B、1个小程序账号,其git仓库能存储多个小程序项目的代码,供开发 6、小程序开发者工具的作用 (1)把小程序体验版-存储到管理后台 (2)把小程序代码-存储到git仓库 附、开发小程序 A、搜索,点击放大镜图标或者ctrl+shift+f B、编辑,点击文件图标 7、小程序管理后台-目录 附、登录网址,https://mp.weixin.qq.com/ 附、管理后台网址,https://mp.weixin.qq.com/wxamp/home/guide (1)小程序账号登录,下面两种登录任选一种 A、使用账号登录,邮箱/微信号 B、微信扫一扫登录,扫后会出现该微信号关联的所有公众号,点击其中一个(登录) (2)登录成功,前往小程序(管理后台),其导航如下 (3)首页 A、小程序信息 未填写//1/3,此处可生成AppID(小程序ID) 补充小程序的基本信息,如名称、图标、描述等 B、小程序类目 未补充 补充小程序的服务类目,设置主营类目 C、小程序备案 未备案 需先填写小程序信息和类目 补充小程序的备案信息,检测是否满足备案条件 D、微信认证 未完善 完成微信认证后,账号可获得“被搜索”和“被分享”能力。未完成微信认证不影响后续版本发布 E、小程序开发与管理 自己开发 开发工具 添加开发者==========非常重要=========== 找服务商开发 立即前往(按钮) (4)管理 A、版本管理 线上版本:尚未提交线上版本 审核版本:你暂无提交审核的版本或者版本已发布上线 开发版本:你尚未上传任何开发版本,可前往开发者工具上传代码。查看介绍, 开发版本:版本号;版本信息;提交审核,下拉(选为体验版本,删除);点击“提交审核/选为体验版本/删除” B、成员管理==========非常重要=========== (5)开发 A、开发管理 开发设置 开发者ID 开发者ID,操作 AppID(小程序ID),wxd9d363f25a//2/3,此处可生成AppID(小程序ID) AppSecret(小程序密钥),生成 小程序代码上传,开发者可基于配置信息调用微信开发者工具提供的代码上传模块。查看详情 配置信息,操作 小程序代码上传密钥,生成 IP白名单,暂无IP白名单,编辑 服务器域名(以下略) 接口设置 B、开发工具 (6)设置 A、基本设置 基本信息 账号信息 AppID(小程序ID),wxd9d363f25a//3/3,此处可生成AppID(小程序ID) 登录邮箱 B、第三方设置 8、小程序管理后台-小程序项目-从创建到保存 //以下操作位置:微信开发者工具 (1)创建 A、首次创建,点击(左上方)项目-扫描二维码-确认登录 B、再次创建,点击(左上方)项目-新建项目/导入项目 (2)填写AppID, 附、以下是AppID生成与获取步骤,任选其一 A、小程序管理后台-首页-小程序信息 B、小程序管理后台-开发-开发管理-开发设置-开发者ID C、小程序管理后台-设置-基本设置-账号信息 (3)勾选用户协议 (4)其它默认 (5)确定 (6)编辑文件 (7)保存(ctrl+s) 9、小程序管理后台-小程序项目-生成版本 //以下操作位置:微信开发者工具 (1)上传项目 A、首次,点击(右上方)上传按钮。上传成功后,需要联系管理员在小程序管理后台将本次上传“设置为体验版本”。确定 B、再次,点击(右上方)上传按钮。上次提交已被选为体验版,本次上传将会覆盖体验版,是否继续?确定 (2)填写版本号、项目备注 (3)点击上传 (4)上传成功、确定 //以下操作位置:管理后台。管理-管理版本-开发版本 附、管理后台网址,https://mp.weixin.qq.com/wxamp/home/guide (5)设置为体验版本 A、左,版本号 B、中,版本信息 C、右,提交审核,选为体验版本、删除 D、点击选为体验版本,体验版设置,点击提交,(点击下载二维码)扫描二维码体验体验版,前往体验,手动关闭弹窗 10、存储仓库-目录 附、git仓库网址,https://git.weixin.qq.com/ (1)项目 A、您的项目 B、关注的项目 C、标星的项目 D、受邀请项目 (2)动态 (3)项目组 (4)里程碑 (5)缺陷 (6)合并请求 (7)代码评审 (8)个人设置 11、存储仓库-存储小程序代码 附、git仓库网址,https://git.weixin.qq.com/ //以下操作位置:代码仓库 (1)进入git仓库 (2)点击创建项目,填写信息,点击创建项目 //以下操作位置:微信开发者工具/本地磁盘的文件夹 (3)配置-Git全局设置。首次创建项目,需执行下列命令。以后创建项目,也会出现下列提示,且配置都相同,但无需执行 git config --global user.name "Z_码农_钱成" git config --global user.email "oncw7ZtkhVxE@git.weixin.qq.com" (4)拉取-别人正在开发的项目代码,协助别人开发。创建一个新的版本库 git clone https://git.weixin.qq.com/13718/xiangmuzu1.git cd xiangmuzu1 touch README.md git add README.md git commit -m "add README" git push -u origin master (5)推送-自己正在开发的项目代码,让别人协助开发。现有的文件夹或Git版本库 cd existing_folder git init git remote add origin https://git.weixin.qq.com/13718/xiangmuzu1.git git add . git commit -m'自定义' git push -u origin master //以下操作位置:微信开发者工具 (6)推送-拉取别人后推送/再次推送自己 A、点击(顶部中间左侧)V形符号 B、点击(顶部中间右侧)...符号 C、点击commit D、点击push 12、存储仓库-删除小程序代码 附、git仓库网址,https://git.weixin.qq.com/ //以下操作位置:代码仓库 (1)进入git仓库 (2)点击“您的项目/关注的项目/标星的项目/受邀请项目” (3)点击某一项目 (4)点击(左下方)设置 (5)点击(右中间)去更改可见性级别 (6)下拉(至最下方),点击删除项目 (7)输入url,点击确定 四、微信小程序-目录说明 来源,https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html 来源,https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html 附、目录结构 ├── app.js ├── app.json ├── app.wxss ├── pages │ │── index │ │ ├── index.wxml │ │ ├── index.js │ │ ├── index.json │ │ └── index.wxss │ └── logs │ ├── logs.wxml │ └── logs.js └── utils 1、 全局配置,一个小程序主体由三个文件组成,必须放在项目的根目录 (1)app.js,小程序全局逻辑 App({ //注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等 onLaunch: function () {},//生命周期回调——监听小程序初始化 onShow: function () {},//生命周期回调——监听小程序启动或切前台 onHide: function () {},//生命周期回调——监听小程序切后台。 onError: function () {},//错误监听函数。 onPageNotFound: function () {},//页面不存在监听函数。 onUnhandledRejection: function () {},//未处理的 Promise 拒绝事件监听函数。 onThemeChange: function () {},//监听系统主题变化 其他: 任意类型,开发者可以添加任意的函数或数据变量到参数中,用this可以访问 }) 附、其它页面,获取实例 // other.js var appInstance = getApp() console.log(appInstance.globalData) // I am global data (2)app.json,小程序全局配置 { "pages": ["pages/index/index", "pages/logs/index"], //小程序的所有页面 "requiredBackgroundModes": ["audio", "location"], "requiredPrivateInfos": [ "getLocation", "onLocationChange", "startLocationUpdateBackground" "chooseAddress" ], "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" //高速公路行驶持续后台定位 } }, "window": { "navigationBarTitleText": "Demo" }, "tabBar": { "height": "50px", "fontSize": "10px", "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/logs/logs", "text": "日志" } ] }, "networkTimeout": { "request": 10000, "downloadFile": 10000 }, "plugins": { //在app.json中声明需要使用的插件 "myPlugin": { "version": "1.0.0", "provider": "wxidxxxxxxxxxxxxxxxx" } }, "debug": true, "resizable": true, //iPad上启用屏幕旋转支持 } (3)app.wxss,小程序全局样式表 2、页面配置,一个小程序页面由四个文件组成 (1)index.js,页面逻辑 page({//组件逻辑用Component({}) data: {}, options: {}, behaviors: String/Array,类似于mixins和traits的组件间代码复用机制, onLoad: function () {}, onShow: function () {}, onReady: function () {}, onHide: function () {}, onUnload: function () {}, onRouteDone: function () {}, onPullDownRefresh: function () {}, onReachBottom: function () {}, onShareAppMessage: function () {}, onShareTimeline: function () {}, onAddToFavorites: function () {}, onPageScroll: function () {}, onResize(res) { //屏幕旋转事件 res.size.windowWidth //新的显示区域宽度 res.size.windowHeight //新的显示区域高度 }, onTabItemTap: function () {}, onSaweexitState: function () {}, onShow: function () {}, //其他: 任意类型,开发者可以添加任意的函数或数据变量到参数中, //在页面的函数中用this可以访问,这部分属性会在页面实例创建时进行一次深拷贝 tapName: function(event) { console.log(event) } }) 附、getCurrentPages,获取当前页面栈,数组中第一个元素为首页,最后一个元素为当前页面 附、Router,页面路由器对象,可以通过this.pageRouter或this.router获得当前页面或自定义组件的路由器对象 (2)index.json,页面配置 { "navigationBarBackgroundColor": "#ffffff", "navigationBarTextStyle": "black", "navigationBarTitleText": "微信接口功能演示", "backgroundColor": "#eeeeee", "backgroundTextStyle": "light" "pageOrientation": "auto", //手机单页面启用屏幕旋转支持 } (3)index.wxss,页面样式表 (4)index.wxml,页面结构 五、微信小程序-WXML语法参考 附、是一套标签语言,结合基础组件、事件系统,可以构建出页面的结构 1、数据绑定,使用Mustache语法(双大括号)将变量包起来 (1)简单绑定 <view> {{ message }} </view> (2)组件属性 <view id="item-{{id}}"> </view> (3)控制属性 <view wx:if="{{condition}}"> </view> (4)关键字 <checkbox checked="{{false}}"> </checkbox> (5)三元运算 <view hidden="{{flag ? true : false}}"> Hidden </view> (6)算数运算 <view> {{a + b}} + {{c}} + d </view> (7)逻辑判断 <view wx:if="{{length > 5}}"> </view> (8)字符串运算 <view>{{"hello" + name}}</view> (9)数据路径运算 <view>{{object.key}} {{array[0]}}</view> (10)组合数组 <view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view> (11)组合对象 <template is="objectCombine" data="{{for: a, bar: b}}"></template> (12)组合对象,后面覆盖前面 <template is="objectCombine" data="{{...obj1, ...obj2, a: 5}}"></template> (13)组合对象 <template is="objectCombine" data="{{foo, bar}}"></template> (14)花括号和引号之间如果有空格,将最终被解析成为字符串 <view wx:for="{{[1,2,3]}} "> {{item}} </view> //等同于 <view wx:for="{{[1,2,3] + ' '}}"> {{item}} </view> (15)当wx:for的值为字符串时,会将字符串解析成字符串数组 <view wx:for="array"> {{item}} </view> //等同于 <view wx:for="{{['a','r','r','a','y']}}"> {{item}} </view> (16)data Page({ data: { message: 'Hello MINA!', id: 0, condition: true, a: 1, b: 2, c: 3, name: 'MINA', object: { key: 'Hello ' }, array: ['MINA'], zero: 0, obj1: { a: 1, b: 2 }, obj2: { c: 3, d: 4 }, foo: 'my-foo', bar: 'my-bar', } }) 2、列表渲染, (1)默认数组的当前项的下标变量名默认为index,数组当前项的变量名默认为item <view wx:for="{{array}}"> {{index}}: {{item.message}} </view> (2)使用wx:for-item可以指定数组当前元素的变量名,使用wx:for-index可以指定数组当前下标的变量名: <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"> {{idx}}: {{itemName.message}} </view> (3)wx:for也可以嵌套,下边是一个九九乘法表 <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i"> <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j"> <view wx:if="{{i <= j}}"> {{i}} * {{j}} = {{i * j}} </view> </view> </view> (4)block wx:for,渲染一个包含多节点的结构块 <block wx:for="{{[1, 2, 3]}}"> <view> {{index}}: </view> <view> {{item}} </view> </block> (5)数据 Page({ data: { array: [{ message: 'foo', }, { message: 'bar' }] } }) (6)wx:key的值以两种形式提供 A、字符串,代表在for循环的array中item的某个property,该property的值需要是列表中唯一的字符串或数字,且不能动态改变 B、保留关键字*this,代表在for循环中的item本身,这种表示需要item本身是一个唯一的字符串或者数字 <switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch> <button bindtap="switch"> Switch </button> <button bindtap="addToFront"> Add to the front </button> <switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch> <button bindtap="addNumberToFront"> Add to the front </button> Page({ data: { objectArray: [ {id: 5, unique: 'unique_5'}, {id: 4, unique: 'unique_4'}, {id: 3, unique: 'unique_3'}, {id: 2, unique: 'unique_2'}, {id: 1, unique: 'unique_1'}, {id: 0, unique: 'unique_0'}, ], numberArray: [1, 2, 3, 4] }, switch: function(e) { const length = this.data.objectArray.length for (let i = 0; i < length; ++i) { const x = Math.floor(Math.random() * length) const y = Math.floor(Math.random() * length) const temp = this.data.objectArray[x] this.data.objectArray[x] = this.data.objectArray[y] this.data.objectArray[y] = temp } this.setData({ objectArray: this.data.objectArray }) }, addToFront: function(e) { const length = this.data.objectArray.length this.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray) this.setData({ objectArray: this.data.objectArray }) }, addNumberToFront: function(e){ this.data.numberArray = [ this.data.numberArray.length + 1 ].concat(this.data.numberArray) this.setData({ numberArray: this.data.numberArray }) } }) 3、条件渲染 (1)使用 wx:if="" 来判断是否需要渲染该代码块: <view wx:if="{{condition}}"> True </view> (2)用 wx:elif 和 wx:else 来添加一个 else 块: <view wx:if="{{length > 5}}"> 1 </view> <view wx:elif="{{length > 2}}"> 2 </view> <view wx:else> 3 </view> (3)用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性 <block wx:if="{{true}}"> <view> view1 </view> <view> view2 </view> </block> <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性 (4)if与hidden,wx:if有更高的切换消耗;hidden有更高的初始渲染消耗 4、模板, WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用 (1)定义模板 使用name属性,作为模板的名字。然后在<template/>内定义代码片段,如: <!-- index: int msg: string time: string --> <template name="msgItem"> <view> <text> {{index}}: {{msg}} </text> <text> Time: {{time}} </text> </view> </template> (2)使用模板 使用is属性,声明需要的使用的模板,然后将模板所需要的data传入 <template is="msgItem" data="{{...item}}"/> Page({ data: { item: { index: 0, msg: 'this is a template', time: '2016-09-15' } } }) (3)is属性可以使用Mustache语法,来动态决定具体需要渲染哪个模板 <template name="odd"> <view> odd </view> </template> <template name="even"> <view> even </view> </template> <block wx:for="{{[1, 2, 3, 4, 5]}}"> <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/> </block> (4)模板的作用域 模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的<wxs/>模块 5、引用 WXML提供两种文件引用方式import和include (1)在 item.wxml 中定义了一个叫item的template <template name="item"> <text>{{text}}</text> </template> (2)在 index.wxml 中引用了 item.wxml,就可以使用item模板 <import src="item.wxml"/> <template is="item" data="{{text: 'forbar'}}"/> (3)import的作用域 import有作用域的概念,只会import目标文件中定义的template,而不会import目标文件import的template <!-- A.wxml --> <template name="A"> <text> A template </text> </template> <!-- B.wxml --> <import src="a.wxml"/> <template name="B"> <text> B template </text> </template> <!-- C.wxml --> <import src="b.wxml"/> <template is="A"/> <!-- Error! Can not use tempalte when not import A. --> <template is="B"/> (4)include include,可以将目标文件除了<template/><wxs/>外的整个代码引入,相当于是拷贝到include位置 <!-- index.wxml --> <include src="header.wxml"/> <view> body </view> <include src="footer.wxml"/> <!-- header.wxml --> <view> header </view> <!-- footer.wxml --> <view> footer </view> 六、微信小程序-WXS语法参考 1、说明 (1)WXS是小程序的一套脚本语言,与JavaScript是不同的语言,有自己的语法 (2)WXS代码可以编写在wxml文件中的<wxs>标签内,或以.wxs为后缀名的文件内 (3)变量、注释、运算符、语句、数据类型、基础类库,与js类似 2、模块 (1)每一个.wxs文件和<wxs>标签都是一个单独的模块 (2)每个模块都有自己独立的作用域,即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见 (3)一个模块要想对外暴露其内部的私有变量与函数,只能通过module.exports实现 (4)在微信开发者工具里面,右键可以直接创建.wxs文件,在其中直接编写WXS脚本 3、.wxs文件 (1)module模块 A、module对象,每个wxs模块均有一个内置的module对象 B、exports属性,通过该属性,可以对外共享本模块的私有变量与函数 /pages/tools.wxs var foo = "'hello world' from tools.wxs"; var bar = function (d) { return d; } module.exports = { FOO: foo, bar: bar, }; module.exports.msg = "some msg"; page/index/index.wxml <wxs src="./../tools.wxs" module="tools" /> <view> {{tools.msg}} </view> <view> {{tools.bar(tools.FOO)}} </view> 页面输出 some msg 'hello world' from tools.wxs (2)require函数 在.wxs模块中引用其他wxs文件模块,可以使用require函数,引用的时候,要注意如下几点 A、只能引用.wxs文件模块,且必须使用相对路径 B、wxs模块均为单例,wxs模块在第一次被引用时,会自动初始化为单例对象;多个页面,多个地方,多次引用,使用的都是同一个wxs模块对象 C、如果一个wxs模块在定义之后,一直没有被引用,则该模块不会被解析与运行 /pages/tools.wxs var foo = "'hello world' from tools.wxs"; var bar = function (d) { return d; } module.exports = { FOO: foo, bar: bar, }; module.exports.msg = "some msg"; /pages/logic.wxs var tools = require("./tools.wxs"); console.log(tools.FOO); console.log(tools.bar("logic.wxs")); console.log(tools.msg); /page/index/index.wxml --> <wxs src="./../logic.wxs" module="logic" /> (3)<wxs>标签的属性 A、module属性,是当前<wxs>标签的模块名, B、src属性,可以用来引用其他的wxs文件模块,引用的时候,要注意如下几点 只能引用.wxs文件模块,且必须使用相对路径 wxs模块均为单例,wxs模块在第一次被引用时,会自动初始化为单例对象;多个页面,多个地方,多次引用,使用的都是同一个wxs模块对象 /pages/index/index.js Page({ data: { msg: "'hello wrold' from js", } }) /pages/index/index.wxml --> <wxs src="./../comm.wxs" module="some_comms"></wxs> 也可以直接使用单标签闭合的写法 <wxs src="./../comm.wxs" module="some_comms" /> 调用some_comms模块里面的bar函数,且参数为some_comms模块里面的 foo <view>{{some_comms.bar(some_comms.foo)}}</view> 调用 some_comms 模块里面的bar函数,且参数为page/index/index.js里面的msg <view>{{some_comms.bar(msg)}}</view> 页面输出: 'hello world' from comm.wxs 'hello wrold' from js 上述例子在文件/page/index/index.wxml中通过<wxs>标签引用了/page/comm.wxs 模块 (4)注意事项 A、<wxs>模块只能在定义模块的WXML文件中被访问到,使用<include>或<import>时,<wxs>模块不会被引入到对应的WXML文件中 B、<template>标签中,只能使用定义该<template>的WXML文件中定义的<wxs>模块 4、引入插件 var myPluginInterface = requirePlugin('myPlugin'); myPluginInterface.hello(); 七、微信小程序-事件系统 来源,https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html 1、什么是事件 (1)事件是视图层到逻辑层的通讯方式,(由用户决定执行逻辑和执行时机) (2)事件可以将用户的行为反馈到逻辑层进行处理 (3)事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数 (4)事件对象可以携带额外信息,如id,dataset,touches 2、事件的使用方式,在组件中绑定一个事件处理函数 (1)JS绑定 以下,在index.wxml中,触发点击事件 <view id="tapTest" data-hi="Weixin" bindtap="tapName"> Click me! </view> 以下,在index.js中,定义点击函数 Page({ tapName: function(event) { console.log(event) } }) (2)WXS绑定 以下,在index.wxml中,引入test.wxs脚本,触发点击事件 <wxs module="wxs" src="./test.wxs"></wxs> <view id="tapTest" data-hi="Weixin" bindtap="{{wxs.tapName}}">绑定的WXS函数必须用{{Mustache语法,Mustache胡子}}括起来</view> 以下,在test.wxs中,定义点击函数 function tapName(event, ownerInstance) { console.log('tap Weixin', JSON.stringify(event)) } module.exports = { tapName: tapName } 3、事件详解 (1)冒泡从里向外,先捕获后冒泡 bind,绑定事件,向上冒泡,后可以紧跟一个冒号,其含义不变,如bind:tap mut-bind,绑定事件,向上冒泡,与上级mut-bind“互斥”的,上级mut-bind不会被触发,上级的其它绑定依然会触发 catch,绑定事件,阻止向上冒泡 (2)冒泡与阻止冒泡,bindtap与catchtap,点击“inner view”会先后调用handleTap3和handleTap2 <view id="outer" bindtap="handleTap1"> “outer view” <view id="middle" catchtap="handleTap2"> “middle view” <view id="inner" bindtap="handleTap3"> “inner view” </view> </view> </view> (3)互斥事件,mut-bind,点击“inner view”会先后调用handleTap3和handleTap2,点击“middle view”会调用handleTap2和handleTap1 <view id="outer" mut-bind:tap="handleTap1"> “outer view” <view id="middle" bindtap="handleTap2"> “middle view” <view id="inner" mut-bind:tap="handleTap3"> “inner view” </view> </view> </view> (4)捕获从外向里,先捕获后冒泡 capture-bind,捕获 capture-catch,中断捕获、取消冒泡 (5)事件的捕获阶段,点击“inner view”会先后调用handleTap2、handleTap4、handleTap3、handleTap1 <view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2"> “outer view” <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4"> “inner view” </view> </view> 如果将上面代码中的第一个capture-bind改为capture-catch,将只触发handleTap2 (6)事件对象,如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象 A、BaseEvent 基础事件对象属性列表 type,代表事件的类型 timeStamp,页面打开到触发事件所经过的毫秒数 target,触发事件的源组件 id,事件源组件的id dataset,事件源组件上由data-开头的自定义属性组成的集合 currentTarget,事件绑定的当前组件 id,当前组件的id dataset,当前组件上由data-开头的自定义属性组成的集合 mark,识别具体触发事件的target节点,承载一些自定义数据,类似于dataset <view mark:myMark="last" bindtap="bindViewTap"> <button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮</button> </view> 在上述WXML中,如果按钮被点击,将触发bindViewTap和bindButtonTap两个事件,事件携带的event.mark将包含myMark和anotherMark两项 Page({ bindViewTap: function(e) { e.mark.myMark === "last" //true e.mark.anotherMark === "leaf" //true } }) //mark,会包含从触发事件的节点到根节点上所有的mark属性值 //dataset,仅包含一个节点的data-属性值 B、CustomEvent 自定义事件对象属性列表(继承 BaseEvent) detail,额外的信息 C、TouchEvent 触摸事件对象属性列表(继承 BaseEvent) touches,触摸事件,当前停留在屏幕中的触摸点信息的数组,每个元素为一个Touch对象,表示当前停留在屏幕上的触摸点 identifier,触摸点的标识符 pageX/pageY,距离文档左上角的距离,文档的左上角为原点 ,横向为X轴,纵向为Y轴 clientX/clientY,距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴 changedTouches,触摸事件,当前变化的触摸点信息的数组 4、WXS响应事件 (1)以下test.wxml <wxs module="test" src="./test.wxs"></wxs> <view bindtouchmove="{{test.touchmove}}" change:prop="{{test.propObserver}}" prop="{{propValue}}" class="movable"></view> //以上,WXS函数必须用{{}}括起来 //以上,change:prop(标签上的监听--自悟),属性前面带“change:”前缀,是在prop属性被设置的时候触发WXS函数,类似Component定义的properties里面的observer属性 //以上,在setData({propValue: newValue})调用之后会触发,而不只是值发生改变,所以在页面初始化的时候会调用一次WxsPropObserver的函数 //以上,在JS里,可以自动调用WXS,因page()而执行 (2)以下test.wxs module.exports = { touchmove: function(event, ownerInstance) { //event.instance,表示触发事件的组件的ComponentDescriptor实例 //ownerInstance,表示的是触发事件的组件所在的组件的ComponentDescriptor实例,如果触发事件的组件是在页面内的,ownerInstance表示的是页面实例 }, propObserver: function(newValue, oldValue, ownerInstance, instance) { //ownerInstance,表示的是触发事件的组件所在的组件的ComponentDescriptor实例,如果触发事件的组件是在页面内的,ownerInstance表示的是页面实例 //instance,表示触发事件的组件的ComponentDescriptor实例 } } //以上,instance.callMethod(funcName:string, args:object),WXS调用当前-组件-在逻辑层(App Service)定义的函数 //以上,ownerInstance.callMethod(funcName:string, args:object),WXS调用当前-页面-在逻辑层(App Service)定义的函数 //以上,在WXS里,可以手动调用JS 八、微信小程序-组件,基础组件 来源,https://developers.weixin.qq.com/miniprogram/dev/component/ 附、<block><block/>,不是组件,只是一个包装元素,不会在页面中做任何的渲染,它能够设置if、for这些控制属性,设置class、id不会生效 1、视图容器 (1)cover-view,覆盖在原生组件之上的文本视图 <view class="page-section page-section-gap"> <map style="width: 100%; height: 300px;" latitude="{{latitude}}" longitude="{{longitude}}" > <cover-view class="cover-view"> <cover-view class="container"> <cover-view class="flex-wrp" style="flex-direction:row;"> <cover-view class="flex-item demo-text-1"></cover-view> <cover-view class="flex-item demo-text-2"></cover-view> <cover-view class="flex-item demo-text-3"></cover-view> </cover-view> </cover-view> </cover-view> </map> </view> (2)match-media,匹配检测节点 <match-media min-width="300" max-width="600"> <view>当页面宽度在 300 ~ 500 px 之间时展示这里</view> </match-media> (3)movable-area,可移动的视图容器,在页面中可以拖拽滑动 <movable-area> <movable-view x="{{x}}" y="{{y}}" direction="all">text</movable-view> </movable-area> (4)scroll-view,可滚动视图区域。类似于轮播图,像素级滑动 <scroll-view scroll-y="true" style="height: 300rpx;" bindscrolltoupper="upper" bindscrolltolower="lower" bindscroll="scroll" scroll-into-view="{{toView}}" scroll-top="{{scrollTop}}"> <view id="demo1" class="scroll-view-item demo-text-1"></view> <view id="demo2" class="scroll-view-item demo-text-2"></view> <view id="demo3" class="scroll-view-item demo-text-3"></view> </scroll-view> (5)swiper,滑块视图容器,swiper-item,仅可放置在swiper组件中,宽高自动设置为100%。类似于轮播图,块级滑动 <swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}"> <block wx:for="{{background}}" wx:key="*this"> <swiper-item> <view class="swiper-item {{item}}"></view> </swiper-item> </block> </swiper> (6)view,视图容器 <view class="container"> <view class="page-body"> <view class="page-section"> <view class="page-section-title"> <text>flex-direction: row\n横向布局</text> </view> <view class="page-section-spacing"> <view class="flex-wrp" style="flex-direction:row;"> <view class="flex-item demo-text-1"></view> <view class="flex-item demo-text-2"></view> <view class="flex-item demo-text-3"></view> </view> </view> </view> <view class="page-section"> <view class="page-section-title"> <text>flex-direction: column\n纵向布局</text> </view> <view class="flex-wrp" style="flex-direction:column;"> <view class="flex-item flex-item-V demo-text-1"></view> <view class="flex-item flex-item-V demo-text-2"></view> <view class="flex-item flex-item-V demo-text-3"></view> </view> </view> </view> </view> 2、基础内容 (1)icon,图标组件 <view class="icon-box"> <icon class="icon-box-img" type="success" size="93"></icon> <view class="icon-box-ctn"> <view class="icon-box-title">成功</view> <view class="icon-box-desc">用于表示操作顺利完成</view> </view> </view> (2)progress,进度条 <view class="progress-box"> <progress percent="20" show-info stroke-width="3"/> </view> (3)rich-text,富文本 <block wx:if="{{renderedByHtml}}"> <rich-text nodes="{{htmlSnip}}"></rich-text> </block> const htmlSnip = `<div class="div_class"> <h1>Title</h1> <p class="p"> Life is <i>like</i> a box of <b> chocolates</b>. </p> </div> ` (4)text,文本 <view class="page-section page-section-spacing"> <view class="text-box" scroll-y="true" scroll-top="{{scrollTop}}"> <text>{{text}}</text> </view> <button disabled="{{!canAdd}}" bindtap="add">add line</button> <button disabled="{{!canRemove}}" bindtap="remove">remove line</button> </view> const texts = [ '2011年1月,微信1.0发布', '同年5月,微信2.0语音对讲发布', '10月,微信3.0新增摇一摇功能', '2012年3月,微信用户突破1亿', '4月份,微信4.0朋友圈发布', '同年7月,微信4.2发布公众平台', '2013年8月,微信5.0发布微信支付', '2014年9月,企业号发布', '同月,发布微信卡包', '2015年1月,微信第一条朋友圈广告', '2016年1月,企业微信发布', '2017年1月,小程序发布', '......' ] 3、表单组件 (1)button,按钮 <view class="button-sp-area"> <button type="primary" plain="true">按钮</button> <button type="primary" disabled="true" plain="true">不可点击的按钮</button> </view> (2)checkbox,多选项目 <label class="checkbox"> <checkbox value="cb" />未选中 </label> <checkbox-group bindchange="checkboxChange"> <label class="weui-cell weui-check__label" wx:for="{{items}}" wx:key="{{item.value}}"> <view class="weui-cell__hd"> <checkbox value="{{item.value}}" checked="{{item.checked}}"/> </view> <view class="weui-cell__bd">{{item.name}}</view> </label> </checkbox-group> (3)checkbox-group,多项选择器,内部由多个checkbox组成,示例见(2) (4)editor,富文本编辑器,可以对图片、文字进行编辑 <editor id="editor" read-only="{{false}}" /> //自写 (5)form,表单 <form catchsubmit="formSubmit" catchreset="formReset"> <view class="page-section page-section-gap"> <view class="page-section-title">switch</view> <switch name="switch"/> </view> <view class="btn-area"> <button style="margin: 30rpx 0" type="primary" formType="submit">Submit</button> <button style="margin: 30rpx 0" formType="reset">Reset</button> </view> </form> (6)input,输入框 <view class="weui-cell weui-cell_input"> <input class="weui-input" auto-focus placeholder="将会获取焦点"/> </view> (7)keyboard-accessory,设置input/textarea聚焦时,键盘上方cover-view/cover-image工具栏视图 <textarea hold-keyboard="{{true}}"> <keyboard-accessory class="container" style="height: 50px;"> <cover-view bindtap="tap" style="flex: 1; background: green;">1</cover-view> <cover-view bindtap="tap" style="flex: 1; background: red;">2</cover-view> </keyboard-accessory> </textarea> (8)label,用来改进表单组件的可用性 <checkbox-group class="group" bindchange="checkboxChange"> <view class="label-1" wx:for="{{checkboxItems}}"> <label> <checkbox value="{{item.name}}" checked="{{item.checked}}"></checkbox> <text class="label-1-text">{{item.value}}</text> </label> </view> </checkbox-group> (9)picker,从底部弹起的滚动选择器 <picker mode="multiSelector" bindchange="bindMultiPickerChange" bindcolumnchange="bindMultiPickerColumnChange" value="{{multiIndex}}" range="{{multiArray}}"> <view class="picker"> 当前选择:{{multiArray[0][multiIndex[0]]}},{{multiArray[1][multiIndex[1]]}},{{multiArray[2][multiIndex[2]]}} </view> </picker> (10)picker-view,嵌入页面的滚动选择器 <picker-view indicator-style="height: 50px;" style="width: 100%; height: 300px;" value="{{value}}" bindchange="bindChange"> <picker-view-column> <view wx:for="{{years}}" wx:key="{{years}}" style="line-height: 50px; text-align: center;">{{item}}年</view> </picker-view-column> <picker-view-column> <view wx:for="{{months}}" wx:key="{{months}}" style="line-height: 50px; text-align: center;">{{item}}月</view> </picker-view-column> </picker-view> (11)picker-view-column,滚动选择器子项 (12)radio,单选项目 <radio-group bindchange="radioChange"> <label class="weui-cell weui-check__label" wx:for="{{items}}" wx:key="{{item.value}}"> <view class="weui-cell__hd"> <radio value="{{item.value}}" checked="true"/> </view> <view class="weui-cell__bd">{{item.name}}</view> </label> </radio-group> (13)radio-group,单项选择器,内部由多个radio组成,示例见(12) (14)slider,滑动选择器 <view class="body-view"> <slider bindchange="slider1change" left-icon="cancel" right-icon="success_no_circle"/> </view> (15)switch,开关选择器 <view class="body-view"> <switch checked="{{switch1Checked}}" bindchange="switch1Change"/> </view> (16)textarea,多行输入框 <view class="section"> <textarea bindblur="bindTextAreaBlur" auto-height placeholder="自动变高" /> </view> 4、导航 (1)functional-page-navigator,仅在插件中有效,用于跳转到插件功能页 <functional-page-navigator name="loginAndGetUserInfo" bind:success="loginSuccess"> <button>登录到插件</button> </functional-page-navigator> (2)navigator,页面链接 <view class="btn-area"> <navigator url="/page/navigate/navigate?title=navigate" hover-class="navigator-hover">跳转到新页面</navigator> <navigator url="../../redirect/redirect/redirect?title=redirect" open-type="redirect" hover-class="other-navigator-hover">在当前页打开</navigator> <navigator url="/page/index/index" open-type="switchTab" hover-class="other-navigator-hover">切换 Tab</navigator> <navigator target="miniProgram" open-type="navigate" app-id="" path="" extra-data="" version="release">打开绑定的小程序</navigator> </view> 5、媒体组件 (1)camera,系统相机。点击相机图标,调出下面页面。出现人像-拍照人像-预览人像-存储人像 <camera device-position="back" flash="off" binderror="error" style="width: 100%; height: 300px;"></camera> <button type="primary" bindtap="takePhoto">拍照</button> <view>预览</view> <image mode="widthFix" src="{{src}}"></image> Page({ takePhoto() { const ctx = wx.createCameraContext() ctx.takePhoto({ quality: 'high', success: (res) => { this.setData({ src: res.tempImagePath }) } }) }, error(e) { console.log(e.detail) } }) (2)image,图片。mode,图片裁剪、缩放的模式 <view class="section section_gap" wx:for="{{array}}" wx:for-item="item"> <view class="section__title">{{item.text}}</view> <view class="section__ctn"> <image style="width: 200px; height: 200px; background-color: #eeeeee;" mode="{{item.mode}}" src="{{src}}"></image> </view> </view> (3)live-player,实时音视频播放 <live-player src="https://domain/pull_stream" mode="RTC" autoplay bindstatechange="statechange" binderror="error" style="width: 300px; height: 225px;" /> (4)live-pusher,实时音视频录制 <live-pusher url="https://domain/push_stream" mode="RTC" autopush bindstatechange="statechange" style="width: 300px; height: 225px;" /> (5)video,视频 <video id="myVideo" src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400" binderror="videoErrorCallback" danmu-list="{{danmuList}}" enable-danmu danmu-btn show-center-play-btn='{{false}}' show-play-btn="{{true}}" controls picture-in-picture-mode="{{['push', 'pop']}}" bindenterpictureinpicture='bindVideoEnterPictureInPicture' bindleavepictureinpicture='bindVideoLeavePictureInPicture' ></video> (6)voip-room,多人音视频对话 <block wx:for="{{openIdList}}" wx:key="*this"> <voip-room openid="{{item}}" mode="{{selfOpenId === item ? 'camera' : 'video'}}"> </voip-room> </block> 6、地图,https://developers.weixin.qq.com/miniprogram/dev/component/map.html 九、微信小程序-自定义组件 来源,开发-指南-自定义组件 来源,https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/ 1、一个小程序自定义组件由四个文件组成,类似于页面Page (1).js,自定义组件逻辑 // page-common-behavior.js // module.exports = Behavior({ //https://developers.weixin.qq.com/miniprogram/dev/reference/api/Behavior.html // properties: {}, //组件的对外属性 // data: {}, //组件的内部数据 // }) var pageCommonBehavior = require('./page-common-behavior') Component({ //来源,https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html //properties,组件的对外属性,是属性名到属性设置的映射表 properties: { //properties,组件的对外属性,是属性名到属性设置的映射表 innerText: { type: String, value: 'default value', } }, //data,组件的内部数据,和properties一同用于组件的模板渲染 data: { someData: {} }, //observers,组件数据字段监听器,用于监听properties和data的变化 observers: { //组件数据字段监听器,用于监听properties和data的变化;普通监听 'numberA, numberB': function(numberA, numberB) {//在 numberA或者numberB被设置时,执行这个函数 this.setData({ sum: numberA + numberB }) } }, observers: { //监听子数据字段 'some.subfield': function(subfield) { //使用 setData 设置 this.data.some.subfield 时触发 //(除此以外,使用 setData 设置 this.data.some 也会触发) subfield === this.data.some.subfield }, 'arr[12]': function(arr12) { //使用 setData 设置 this.data.arr[12] 时触发 //(除此以外,使用 setData 设置 this.data.arr 也会触发) arr12 === this.data.arr[12] }, }, observers: { //监听所有子数据字段的变化,可以使用通配符 ** 'some.field.**': function(field) { //使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发 //(除此以外,使用 setData 设置 this.data.some 也会触发) field === this.data.some.field }, }, observers: { //仅使用通配符 ** 可以监听全部 setData '**': function() { //每次 setData 都触发 }, }, //methods,组件的方法,包括事件响应函数和任意的自定义方法 methods: { customMethod: function(){ this.setData({ //设置data并执行视图层渲染 s: false }) this.hasBehavior() //检查组件是否具有behavior(检查时会递归检查被直接或间接引入的所有behavior) this.triggerEvent() //触发事件 } }, //behaviors,组件间可共享的部分,组件间代码复用机制,类似于mixins和traits //behaviors,组件引用它时,它的properties、data、method会被合并到组件对应的配置中,生命周期函数也会在对应时机被调用 behaviors: [pageCommonBehavior], behaviors: ['wx://form-field'], //它使得这个自定义组件有类似于表单控件的行为 //lifetimes,组件生命周期-声明对象,里面的生命周期可以写到外面,但写在这里优先级更高 lifetimes: {//生命周期函数,可以为函数,或一个在methods段中定义的方法名 //created,在组件实例刚刚被创建时执行,此时不能调用setData created: function() {}, //attached,在组件实例进入页面节点树时执行,声明的字段会被lifetimes声明的字段覆盖 attached: function() { this.setData({ numberA: 1, numberB: 2, }) this.setData({ //这样会触发上面的 observer 'some.field': { /* ... */ } }) this.setData({ //这样也会触发上面的 observer 'some.field.xxx': { /* ... */ } }) this.setData({ //这样还是会触发上面的 observer 'some': { /* ... */ } }) }, //ready,组件布局完成后执行 ready: function() { }, //moved,组件实例被移动到节点树另一个位置时执行 moved: function() { }, //detached,组件实例被从页面节点树移除时执行 detached: function() { }, }, pageLifetimes: {// 组件所在页面的生命周期函数 show: function () { }, //组件所在的页面被展示时执行 hide: function () { }, //组件所在的页面被隐藏时执行 resize(res) { //屏幕旋转事件 res.size.windowWidth //新的显示区域宽度 res.size.windowHeight //新的显示区域高度 } routeDone: function () { }, //组件所在页面路由动画完成时执行 }, // 组件实例的属性和方法可以在组件的方法、生命周期函数和属性observer中通过this访问 // 属性名 // is,组件的文件路径 // id,节点id // dataset,节点dataset // data,组件数据,包括内部数据和属性值 // properties,组件数据,包括内部数据和属性值(与data一致) // router,相对于当前自定义组件的Router对象 // pageRouter,相对于当前自定义组件所在页面的Router对象 // renderer,渲染当前组件的渲染后端 // 方法名 // setData,设置data并执行视图层渲染 // hasBehavior,检查组件是否具有behavior(检查时会递归检查被直接或间接引入的所有behavior) // triggerEvent,触发事件,参见,组件间通信与事件, // https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html }) (2).json,自定义组件配置 { "component": true//这一组文件为自定义组件 } (3).wxss,自定义组件样式表 .inner { color: red; } (4).wxml,自定义组件结构 <view class="inner"> <view>这里是组件的内部节点</view> <slot></slot> </view> (5)自定义组件使用 以下,在页面的.json文件中声明引用 { "usingComponents": { "component-tag-name": "path/to/the/custom/component" } } 以下,在页面的.wxml文件中使用 <view> <component-tag-name inner-text="Some text">这是插槽内容</component-tag-name> </view> (6)自定义组件扩展 //提供了修改自定义组件定义段的能力,下面例子就是修改了自定义组件中的data定义段里的内容 //behavior.js module.exports = Behavior({ definitionFilter(defFields) { defFields.data.from = 'behavior' }, }) //component.js Component({ data: { from: 'component' }, behaviors: [require('behavior.js')], ready() { console.log(this.data.from) //此处会发现输出 behavior 而不是 component } }) (7)简易双向绑定,自定义组件将自身的myValue属性双向绑定到了组件内输入框的value属性上 custom-component定义,<input model:value="{{myValue}}" /> custom-component使用,<custom-component model:my-value="{{pageValue}}" /> 2、抽象节点, 有默认渲染内容,使用者决定渲染内容,与插槽相似 (1)自定义组件 <!-- selectable-group.json --> { "componentGenerics": {//generic,通用 "selectable": true } } { "componentGenerics": { "selectable": { /* 默认抽象节点 */ "default": "path/to/default/component" } } } <!-- selectable-group.wxml 渲染抽象节点 --> <view wx:for="{{labels}}"> <label> <selectable disabled="{{false}}"></selectable> {{item}} </label> </view> (2)父组件 <!-- parent.json 定义抽象节点 --> { "usingComponents": { "custom-radio": "path/to/custom/radio", "custom-checkbox": "path/to/custom/checkbox" } } <!-- parent.wxml 选择抽象节点 --> <selectable-group generic:selectable="custom-radio" /> 3、组件间通信与事件 (1)父级 <!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 --> <component-tag-name bindmyevent="onMyEvent" /> <!-- 或者可以写成 --> <component-tag-name bind:myevent="onMyEvent" /> Page({ onMyEvent: function(e){ e.detail //自定义组件触发事件时提供的detail对象 } }) (2)自身 <button bindtap="onTap">点击这个按钮将触发“myevent”事件</button> Component({ properties: {}, methods: { onTap: function(){ var myEventDetail = {} //detail对象,提供给事件监听函数 var myEventOption = {} //触发事件的选项 this.triggerEvent('myevent', myEventDetail, myEventOption) //trigger,触发 } } }) 十、微信小程序-API 1、基础 (1)系统 A、wx.getWindowInfo() //获取窗口信息 B、wx.getSystemInfo(Object object) // 获取系统信息。是异步的调用格式,但是是同步返回 C、wx.getDeviceInfo() //获取设备基础信息 D、wx.getAppBaseInfo() //获取微信APP基础信息 (2)更新 A、wx.updateWeChatApp(Object object) //更新客户端版本 B、wx.getUpdateManager() //获取全局唯一的版本更新管理器,用于管理小程序更新 (3)小程序 A、wx.getApiCategory() //获取当前API类别 B、wx.onThemeChange(function listener) //监听系统主题改变事件。该事件与App.onThemeChange的回调时机一致 C、wx.onAppShow(function listener) //监听小程序切前台事件。该事件与App.onShow的回调参数一致 (4)调试 A、console.log() //向调试面板中打印log日志 B、console.warn() //向调试面板中打印warn日志 (5)性能 A、wx.preloadWebview(Object object) //预加载下个页面的WebView B、wx.getPerformance() //获取当前小程序性能相关的信息 C、wx.preloadAssets(Object object) //为视图层预加载媒体资源文件 2、路由 (1)wx.switchTab(Object object) //跳转到tabBar页面,并关闭其他所有非tabBar页面 (2)wx.reLaunch(Object object) //关闭所有页面,打开到应用内的某个页面 (3)wx.redirectTo(Object object) //关闭当前页面,跳转到应用内的某个页面,但是不允许跳转到tabbar页面 (4)wx.navigateTo(Object object) //保留当前页面,跳转到应用内的某个页面,但是不能跳到tabbar页面,使用wx.navigateBack可以返回到原页面 (5)wx.navigateBack(Object object) //关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages获取当前的页面栈,决定需要返回几层。 (6)自定义路由 A、wx.router //获取router对象 B、router.addRouteBuilder(string routeType, function routeBuilder) //添加自定义路由配置 wx.router.addRouteBuilder('slide', slideRouteBuilder) //路由类型,路由动画定义函数 C、router.getRouteContext(Object this) //获取页面对应的自定义路由上下文对象 D、router.removeRouteBuilder(string routeType) //移除自定义路由配置 wx.router.removeRouteBuilder('slide') 3、跳转 (1)wx.restartMiniProgram(Object object) //重启当前小程序 (2)wx.openEmbeddedMiniProgram(Object object) //打开半屏小程序 (3)wx.navigateToMiniProgram(Object object) //打开另一个小程序 (4)wx.exitMiniProgram(Object object) //退出当前小程序。必须有点击行为才能调用成功 4、转发 (1)wx.updateShareMenu(Object object) //更新转发属性 (2)wx.showShareMenu(Object object) //显示当前页面的转发按钮 (3)wx.shareVideoMessage(Object object) //转发视频到聊天 (4)wx.shareFileMessage(Object object) //转发文件到聊天 5、界面 (1)交互 A、wx.showToast(Object object) //显示消息提示框 B、wx.showModal(Object object) //显示模态对话框 C、wx.showLoading(Object object) //显示loading提示框。需主动调用wx.hideLoading才能关闭提示框 D、wx.showActionSheet(Object object) //显示操作菜单 E、wx.hideToast(Object object) //隐藏消息提示框 F、wx.hideLoading(Object object) //隐藏loading提示框 (2)导航栏 A、wx.showNavigationBarLoading(Object object) //在当前页面显示导航条加载动画 B、wx.setNavigationBarTitle(Object object) //动态设置当前页面的标题 C、wx.setNavigationBarColor(Object object) //设置页面导航条颜色 D、wx.hideNavigationBarLoading(Object object) //在当前页面隐藏导航条加载动画 E、wx.hideHomeButton(Object object) //隐藏返回首页按钮 (3)背景 A、wx.setBackgroundTextStyle(Object object) //动态设置下拉背景字体、loading图的样式 B、wx.setBackgroundColor(Object object) //动态设置窗口的背景色 (4)Tab Bar,位于小程序底部的导航栏菜单 A、wx.showTabBarRedDot(Object object) //显示tabBar某一项的右上角的红点 B、wx.showTabBar(Object object) //显示tabBar C、wx.setTabBarStyle(Object object) //动态设置tabBar的整体样式 D、wx.setTabBarItem(Object object) //动态设置tabBar某一项的内容 E、wx.setTabBarBadge(Object object) //为tabBar某一项的右上角添加文本 F、wx.removeTabBarBadge(Object object) //移除tabBar某一项右上角的文本 G、wx.hideTabBarRedDot(Object object) //隐藏tabBar某一项的右上角的红点 H、wx.hideTabBar(Object object) //隐藏tabBar (5)字体 A、wx.loadFontFace(Object object) //动态加载网络字体,文件地址需为下载类型。需在app.js中调用 (6)下拉刷新 A、wx.stopPullDownRefresh(Object object) //停止当前页面下拉刷新 B、wx.startPullDownRefresh(Object object) //开始下拉刷新。调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。 (7)滚动 A、wx.pageScrollTo(Object object) //将页面滚动到目标位置,支持选择器和滚动距离两种方式定位 (8)动画 A、wx.createAnimation(Object object) //创建一个动画实例animation (9)置顶 A、wx.setTopBarText(Object object) //动态设置置顶栏文字内容 (10)自定义组件 A、wx.nextTick(Object object) //延迟一部分操作到下一个时间片再执行。(类似于setTimeout) (11)菜单 A、wx.getMenuButtonBoundingClientRect(Object object) //获取菜单按钮(右上角胶囊按钮)的布局位置信息。坐标信息以屏幕左上角为原点。 (12)窗口 A、wx.setWindowSize(Object object) //设置窗口大小,该接口仅适用于PC平台 B、wx.onWindowResize(Object object) //窗口尺寸变化事件的监听函数 C、wx.offWindowResize(Object object) //移除窗口尺寸变化事件的监听函数 D、wx.checkIsPictureInPictureActive(Object object) //返回当前是否存在小窗播放(小窗在video/live-player/live-pusher下可用) (13)worklet 动画 A、wx.worklet(Object object) //获取worklet对象 6、网络 (1)发起请求,wx.request(Object object) //发起HTTPS网络请求 wx.request({ url: 'example.php', data: { x: '', y: '' }, header: { 'content-type': 'application/json' // 默认值 }, timeout: 60000, //默认值 method: 'get', //默认值 dataType: 'text', //默认值。返回的数据格式,即res.data,返回的数据为JSON时,返回后会对返回的数据进行一次 JSON.parse responseType: 'text', //默认值。响应的数据类型,即res, enableProfil: true, //是否开启profile,默认开启 success (res) { console.log(res.profile) //网络连接过程中关键时间点的耗时信息 }, false (res) { console.log(res.errMsg) } }) (2)wx.downloadFile(Object object) //下载文件资源到本地 const DownloadTask = wx.downloadFile({ url: 'https://example.com/audio/123', filePath: '指定文件下载后存储的路径(本地路径)', enableProfil: true, //是否开启profile,默认开启 success (res) { //只要服务器有响应数据,就会把响应内容写入文件并进入success回调,业务需要自行判断是否下载到了想要的内容 console.log(res.profile) //网络连接过程中关键时间点的耗时信息 if(res.statusCode === 200) { wx.playVoice({ filePath: res.tempFilePath }) } }, }) //DownloadTask.onProgressUpdate(function listener),监听下载进度变化事件 (3)wx.uploadFile(Object object) //将本地资源上传到服务器 wx.chooseImage({ success (res) { const tempFilePaths = res.tempFilePaths const UploadTask = wx.uploadFile({ url: 'https://example.weixin.qq.com/upload', //仅为示例,非真实的接口地址 filePath: tempFilePaths[0], name: 'file', formData: { 'user': 'test' }, enableProfil: true, //是否开启profile,默认开启 success (res){ const data = res.data //do something } }) //UploadTask.onProgressUpdate(function listener),监听上传进度变化事件 } }) (4)WebSocket //通过WebSocket连接发送数据 let socketOpen = false let socketMsgQueue = [] wx.connectSocket({ url: 'test.php' }) wx.onSocketOpen(function(res) { socketOpen = true for (let i = 0; i < socketMsgQueue.length; i++){ sendSocketMessage(socketMsgQueue[i]) } socketMsgQueue = [] }) function sendSocketMessage(msg) { if (socketOpen) { wx.sendSocketMessage({ data:msg }) } else { socketMsgQueue.push(msg) } } 7、支付 (1)wx.requestVirtualPayment(Object object),发起米大师虚拟支付 (2)wx.requestPluginPayment(Object object),插件中发起支付 (3)wx.requestPayment(Object object),发起微信支付 (4)wx.requestMerchantTransfer(Object object),商家转账用户确认模式下,在微信客户端通过小程序拉起页面请求用户确认收款 //调用前需在微信支付商户平台/合作伙伴平台-产品中心,申请开通商家转账 (5)wx.requestCommonPayment(Object object),发起通用支付 8、数据缓存 (1)wx.setStorageSync(string key, any data) //将数据存储在本地缓存中指定的key中,数据都一直可用 wx.setStorageSync('key', 'value') (2)wx.setStorage(Object object) //将数据存储在本地缓存中指定的key中,数据都一直可用 wx.setStorage({ key:"key", data:"value" }) wx.setStorage({ //开启加密存储 key: "key", data: "value", encrypt: true, //若开启加密存储,setStorage和getStorage需要同时声明encrypt的值为true success() { wx.getStorage({ key: "key", encrypt: true, //若开启加密存储,setStorage和getStorage需要同时声明encrypt的值为true success(res) { console.log(res.data) } }) } }) (3)wx.getStorageSync(string key) //从本地缓存中同步获取指定key的内容 (4)wx.getStorage(Object object) //从本地缓存中异步获取指定key的内容 9、数据分析 10、XR-FRAME 11、画布 12、媒体 (1)地图 A、wx.createMapContext(string mapId, Object this) //创建map上下文MapContext对象。 //建议使用“wx.createSelectorQuery”-1,获取context对象。 (2)图片 A、wx.saveImageToPhotosAlbum(Object object) //保存图片到系统相册 B、wx.previewMedia(Object object) //预览图片和视频 C、wx.previewImage(Object object) //在新页面中全屏预览图片。预览的过程中用户可以进行保存图片、发送给朋友等操作 D、wx.getImageInfo(Object object) //获取图片信息。网络图片需先配置download域名才能生效 E、wx.editImage(Object object) //编辑图片接口 F、wx.cropImage(Object object) //裁剪图片接口 G、wx.compressImage(Object object) //压缩图片接口,可选压缩质量 H、wx.chooseMessageFile(Object object) //从客户端会话选择文件 I、wx.chooseImage(Object object) //从本地相册选择图片或使用相机拍照,请使用wx.chooseMedia代替 (3)视频 A、wx.saveVideoToPhotosAlbum(Object object) //保存视频到系统相册。支持mp4视频格式 B、wx.openVideoEditor(Object object) //打开视频编辑器 C、wx.getVideoInfo(Object object) //获取视频详细信息 D、wx.createVideoContext(string id, Object this) //创建video上下文VideoContext对象。 //建议使用“wx.createSelectorQuery”-1,获取context对象。 E、wx.compressVideo(Object object) //压缩视频接口 F、wx.chooseVideo(Object object) //拍摄视频或从手机相册中选视频,请使用wx.chooseMedia代替 G、wx.chooseMedia(Object object) //拍摄或从手机相册中选择图片或视频 (4)音频 A、wx.stopVoice(Object object) //结束播放语音,请使用wx.createInnerAudioContext代替 B、wx.setInnerAudioOption(Object object) //设置InnerAudioContext的播放选项。设置之后对当前小程序全局生效。 C、wx.playVoice(Object object) //开始播放语音,请使用wx.createInnerAudioContext代替 D、wx.pauseVoice(Object object) //暂停正在播放的语音,请使用wx.createInnerAudioContext代替 E、wx.getAvailableAudioSources(Object object) //获取当前支持的音频输入源 F、wx.createWebAudioContext() //创建WebAudio上下文 G、wx.createMediaAudioPlayer() //创建媒体音频播放器对象MediaAudioPlayer对象,可用于播放视频解码器VideoDecoder输出的音频 H、wx.createInnerAudioContext(Object object) //创建内部audio上下文InnerAudioContext对象 I、wx.createAudioContext(string id, Object this) //创建audio上下文AudioContext对象,请使用wx.createInnerAudioContext代替 (5)背景音频 A、wx.stopBackgroundAudio(Object object) //停止播放音乐,请使用wx.getBackgroundAudioManager代替 B、wx.seekBackgroundAudio(Object object) //控制音乐播放进度,请使用wx.getBackgroundAudioManager代替 C、wx.playBackgroundAudio(Object object) //使用后台播放器播放音乐,请使用wx.getBackgroundAudioManager代替 D、wx.pauseBackgroundAudio(Object object) //暂停播放音乐,请使用wx.getBackgroundAudioManager代替 E、wx.onBackgroundAudioStop(function listener) //监听音乐停止事件,请使用wx.getBackgroundAudioManager代替 F、wx.onBackgroundAudioPlay(function listener) //监听音乐播放事件,请使用wx.getBackgroundAudioManager代替 G、wx.onBackgroundAudioPause(function listener) //监听音乐暂停事件,请使用wx.getBackgroundAudioManager代替 H、wx.getBackgroundAudioPlayerState(Object object) //获取后台音乐播放状态,请使用wx.getBackgroundAudioManager代替 I、wx.getBackgroundAudioManager() //获取全局唯一的背景音频管理器 (6)实时音视频 A、wx.createLivePusherContext() //创建live-pusher上下文LivePusherContext对象 B、wx.createLivePlayerContext(string id, Object this) //创建live-player上下文LivePlayerContext对象 //建议使用“wx.createSelectorQuery”-1,获取context对象 (7)录音 A、wx.stopRecord(Object object) //停止录音,请使用wx.getRecorderManager代替 B、wx.startRecord(Object object) //开始录音,请使用wx.getRecorderManager代替 C、wx.getRecorderManager() //获取全局唯一的录音管理器RecorderManager (8)相机 A、wx.createCameraContext() //创建camera上下文CameraContext对象 (9)富文本 <editor id="editor" /> //自写 const EditorContext = wx.createSelectorQuery() EditorContext.select('#editor') A、EditorContext.blur(Object object) //编辑器失焦,同时收起键盘 B、EditorContext.clear(Object object) //清空编辑器内容 C、EditorContext.format(string name, string value) //修改样式 D、EditorContext.getContents(Object object) //获取编辑器内容 E、EditorContext.getSelectionText(Object object) //获取编辑器已选区域内的纯文本内容 F、EditorContext.insertDivider(Object object) //插入分割线 G、EditorContext.insertImage(Object object) //插入图片 H、EditorContext.insertText(Object object) //覆盖当前选区,设置一段文本 I、EditorContext.redo(Object object) //恢复 J、EditorContext.removeFormat(Object object) //清除当前选区的样式 K、EditorContext.scrollIntoView() //使得编辑器光标处滚动到窗口可视区域内 L、EditorContext.setContents(Object object) //初始化编辑器内容,html和delta同时存在时仅delta生效 M、EditorContext.undo(Object object) //撤销 N、 (10)音视频合成 A、wx.createMediaContainer() //创建音视频处理容器,最终可将容器中的轨道合成一个视频 (11)实时语音,下面接口不完整 A、wx.updateVoIPChatMuteConfig(Object object) //更新实时语音静音设置 B、wx.subscribeVoIPVideoMembers(Object object) //订阅视频画面成员 (12)画面录制器 A、wx.createMediaRecorder(Object canvas, Object options) //创建WebGL画面录制器,可逐帧录制在WebGL上渲染的画面并导出视频文件 (13)视频解码器 A、wx.createVideoDecoder() //创建视频解码器,可逐帧获取解码后的数据 13、位置,下面接口不完整 (1)wx.stopLocationUpdate(Object object) //关闭监听实时位置变化,前后台都停止消息接收 (2)wx.startLocationUpdate(Object object) //开启小程序进入前台时接收位置消息 (3)wx.openLocation(Object object) //使用微信内置地图查看位置 (4)wx.getLocation(Object object) //获取当前的地理位置、速度 14、文件 (1)wx.saveFileToDisk(Object object) //保存文件系统的文件到用户磁盘,仅在PC端支持 (2)wx.openDocument(Object object) //新开页面打开文档 (3)wx.getFileSystemManager() //获取全局唯一的文件管理器 15、开放接口 (1)登录 A、wx.pluginLogin(Object args) //该接口仅在小程序插件中可调用,调用接口获得插件用户标志凭证(code) B、wx.login(Object object) //调用接口获取登录凭证(code) C、wx.checkSession(Object object) //检查登录态是否过期 (2)账号信息 A、wx.getAccountInfoSync() //获取当前账号信息 (3)用户信息 A、wx.getUserProfile(Object object) //获取用户信息 B、wx.getUserInfo(Object object) //获取用户信息 (4)授权 A、wx.authorizeForMiniProgram //仅小程序插件中能调用该接口,用法同wx.authorize。目前仅支持三种scope wx.authorizeForMiniProgram({ scope: 'scope.record', //scope.record、scope.writePhotosAlbum、scope.camera success () { //用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问 wx.startRecord() } }) B、wx.authorize //提前向用户发起授权请求 //可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope wx.getSetting({ success(res) { if (!res.authSetting['scope.record']) { wx.authorize({ scope: 'scope.record', success () { // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问 wx.startRecord() } }) } } }) (5)设置 A、wx.openSetting //功能描述,调起客户端小程序设置界面,返回用户设置的操作结果 wx.openSetting({ success (res) { console.log(res.authSetting) // res.authSetting = { // "scope.userInfo": true, // "scope.userLocation": true // } } }) B、wx.getSetting //获取用户的当前设置 (6)收货地址 A、wx.chooseAddress(Object object) //获取用户收货地址 (7)卡券 A、wx.openCard(Object object) //查看微信卡包中的卡券 B、wx.addCard(Object object) // (8)发票 A、wx.chooseInvoiceTitle(Object object) //选择用户的发票抬头 B、wx.chooseInvoice(Object object) //选择用户已有的发票 (9)生物认证 A、wx.startSoterAuthentication(Object object) //开始SOTER生物认证 B、wx.checkIsSupportSoterAuthentication(Object object) //获取本机支持的SOTER生物认证方式 C、wx.checkIsSoterEnrolledInDevice(Object object) //获取设备内是否录入如指纹等生物信息的接口 (10)微信运动 A、wx.shareToWeRun(Object object) //分享数据到微信运动 B、wx.getWeRunData(Object object) //获取用户过去三十一天微信运动步数 (11)订阅消息 A、wx.requestSubscribeMessage(Object object) //调起客户端小程序订阅消息界面,返回用户订阅消息的操作结果 B、wx.requestSubscribeDeviceMessage(Object object) //订阅设备消息接口,调用后弹出授权框,用户同意后会允许开发者给用户发送订阅模版消息 (12)微信红包 A、wx.showRedPackage(Object object) //拉取h5领取红包封面页 (13)收藏 A、wx.addVideoToFavorites(Object object) //收藏视频 B、wx.addFileToFavorites(Object object) //收藏文件 (14)我的小程序 A、wx.checkIsAddedToMyMiniProgram(Object object) //检查小程序是否被添加至 「我的小程序」 (15)车牌 A、wx.chooseLicensePlate(Object object) //选择车牌号 (16)视频号 A、wx.reserveChannelsLive(Object object) //预约视频号直播 B、wx.openChannelsUserProfile(Object object) //打开视频号主页 C、wx.openChannelsLive(Object object) //打开视频号直播 D、wx.openChannelsEvent(Object object) //打开视频号活动页 E、wx.openChannelsActivity(Object object) //打开视频号视频 F、wx.getChannelsShareKey(Object object) //获取视频号直播卡片/视频卡片的分享来源 G、wx.getChannelsLiveNoticeInfo(Object object) //获取视频号直播预告信息 H、wx.getChannelsLiveInfo(Object object) //获取视频号直播信息 (17)音视频通话 A、wx.requestDeviceVoIP(Object object) //请求用户授权与设备(组)间进行音视频通话 B、wx.getDeviceVoIPList(Object object) //查询当前用户授权的音视频通话设备(组)信息 (18)微信群 A、wx.getGroupEnterInfo(Object object) //获取微信群聊场景下的小程序启动信息 (19)隐私信息授权 A、wx.requirePrivacyAuthorize(Object object) //模拟隐私接口调用,并触发隐私弹窗逻辑 B、wx.openPrivacyContract(Object object) //跳转至隐私协议页面 C、wx.onNeedPrivacyAuthorization(function listener) //监听隐私接口需要用户授权事件 D、wx.getPrivacySetting(Object object) //查询隐私授权情况 (20)微信客服 A、wx.openCustomerServiceChat(Object object) //打开微信客服,页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用 (21)微信表情 A、wx.openStickerSetView(Object object) //打开表情专辑 B、wx.openStickerIPView(Object object) //打开表情IP合辑 C、wx.openSingleStickerView(Object object) //打开单个表情 16、设备 (1)蓝牙-通用 (2)蓝牙-低功耗中心设备 (3)蓝牙-低功耗外围设备 (4)蓝牙-信标(Beacon) (5)NFC读写 A、wx.getNFCAdapter() //获取NFC实例 (6)Wi-Fi(wifi),无线保真(Wireless Fidelity),下面接口不完整 A、wx.stopWifi(Object object) //关闭wifi模块 B、wx.startWifi(Object object) //初始化wifi模块 C、wx.setWifiList(Object object) //设置wifiList中 AP 的相关信息,iOS特有接口 D、wx.getWifiList(Object object) //请求获取wifi列表 E、wx.getConnectedWifi(Object object) //获取已连接中的wifi信息 (7)日历 (8)联系人 A、wx.chooseContact(Object object) //拉起手机通讯录,选择联系人 B、wx.addPhoneContact(Object object) //添加手机通讯录联系人 (9)无障碍 A、wx.checkIsOpenAccessibility(Object object) //检测是否开启视觉无障碍功能 (10)电量 A、wx.getBatteryInfoSync() //同步获取设备电量 B、wx.getBatteryInfo(Object object) //获取设备电量 (11)剪贴板 A、wx.setClipboardData(Object object) //设置系统剪贴板的内容 B、wx.getClipboardData(Object object) //获取系统剪贴板的内容 (12)NFC主机卡模拟 (13)网络 A、wx.onNetworkWeakChange(function listener) //监听弱网状态变化事件 B、wx.onNetworkStatusChange(function listener) //监听网络状态变化事件 C、wx.offNetworkWeakChange(function listener) //移除弱网状态变化事件的监听函数 D、wx.offNetworkStatusChange(function listener) //移除网络状态变化事件的监听函数 E、wx.getNetworkType(Object object) //获取网络类型 F、wx.getLocalIPAddress(Object object) // (14)加密 A、wx.getRandomValues(Object object) //获取密码学安全随机数 (15)屏幕 A、wx.setVisualEffectOnCapture(Object object) //wx.setVisualEffectOnCapture(Object object) B、wx.setScreenBrightness(Object object) //设置屏幕亮度 C、wx.setKeepScreenOn(Object object) //设置是否保持常亮状态 D、wx.onUserCaptureScreen(function listener) //监听用户主动截屏事件 E、wx.onScreenRecordingStateChanged(function listener) //监听用户录屏事件 F、wx.offUserCaptureScreen(function callback) //取消监听用户主动截屏事件 G、wx.offScreenRecordingStateChanged(function listener) //移除用户录屏事件的监听函数 H、wx.getScreenRecordingState(Object object) //查询用户是否在录屏 I、wx.getScreenBrightness(Object object) //获取屏幕亮度 (16)键盘 A、wx.onKeyboardHeightChange(function listener) //监听键盘高度变化事件 B、wx.offKeyboardHeightChange(function listener) //移除键盘高度变化事件的监听函数 C、wx.hideKeyboard(Object object) //在input、textarea等focus拉起键盘之后,手动调用此接口收起键盘 D、wx.getSelectedTextRange(Object object) //在input、textarea等focus之后,获取输入框的光标位置 (17)电话 A、wx.makePhoneCall(Object object) //拨打电话 (18)加速计,例如摇一摇 A、wx.stopAccelerometer(Object object) //停止监听加速度数据 B、wx.startAccelerometer(Object object) //开始监听加速度数据 C、wx.onAccelerometerChange(function listener) //监听加速度数据事件 D、wx.offAccelerometerChange(function listener) //移除加速度数据事件的监听函数 (19)罗盘 A、wx.stopCompass(Object object) //停止监听罗盘数据 B、wx.startCompass(Object object) //开始监听罗盘数据 C、wx.onCompassChange(function listener) //罗盘数据变化事件的监听函数 D、wx.offCompassChange(function listener) //移除罗盘数据变化事件的监听函数 (20)设备方向 A、wx.stopDeviceMotionListening(Object object) //停止监听设备方向的变化 B、wx.startDeviceMotionListening(Object object) //开始监听设备方向的变化 C、wx.onDeviceMotionChange(function listener) //监听设备方向变化事件 D、wx.offDeviceMotionChange(function listener) //移除设备方向变化事件的监听函数 (21)陀螺仪,测量偏转、倾斜时的转动角速度 A、wx.stopGyroscope(Object object) //停止监听陀螺仪数据 B、wx.startGyroscope(Object object) //开始监听陀螺仪数据 C、wx.onGyroscopeChange(function listener) //监听陀螺仪数据变化事件 D、wx.offGyroscopeChange(function listener) //移除陀螺仪数据变化事件的监听函数 (22)内存 A、wx.onMemoryWarning(function listener) //监听内存不足告警事件 B、wx.offMemoryWarning(function listener) //移除内存不足告警事件的监听函数 (23)扫码 A、wx.scanCode(Object object) //调起客户端扫码界面进行扫码 (24)短信 A、wx.sendSms(Object object) //拉起手机发送短信界面 (25)振动 A、wx.vibrateShort(Object object) //使手机发生较短时间的振动(15 ms) B、wx.vibrateLong(Object object) //使手机发生较长时间的振动(400 ms) 17、AI (1)AI推理 A、wx.getInferenceEnvInfo(Object object) //获取通用AI推理引擎版本 B、wx.createInferenceSession(Object object) //创建AI推理Session (2)视觉算法 A、wx.isVKSupport(string version) //判断支持版本 B、wx.createVKSession(Object object) //创建vision kit会话对象 (3)人脸检测 A、wx.stopFaceDetect(Object object) //停止人脸检测。本接口不再维护,请使用wx.createVKSession接口代替 B、wx.initFaceDetect(Object object) //初始化人脸检测。本接口不再维护,请使用wx.createVKSession接口代替 C、wx.faceDetect(Object object) //人脸检测。本接口不再维护,请使用wx.createVKSession接口代替 18、Worker function createNewWorker() { const worker = wx.createWorker('workers/index.js', { //创建一个Worker线程 useExperimentalWorker: true }) //监听worker被系统回收事件 worker.onProcessKilled(() => { //重新创建一个worker createNewWorker() }) } //创建实验worker createNewWorker() 19、WXML const query = wx.createSelectorQuery() //返回一个SelectorQuery对象实例。在自定义组件或包含自定义组件的页面中,应使用this.createSelectorQuery()来代替 query.select('#the-id').boundingClientRect() query.selectViewport().scrollOffset() query.exec(function(res){ res[0].top //#the-id节点的上边界坐标 res[1].scrollTop //显示区域的竖直滚动位置 }) 20、第三方平台 21、广告 22、Skyline 十一、uniapp跨端框架-简介 来源,https://gitee.com/dcloud/uni-app/tags?page=60 来源,https://uniapp.dcloud.net.cn/history.html 来源,https://uniapp.dcloud.net.cn/tutorial/ 1、uni-app的产生背景 注、Dcloud一般指数字天堂(北京)网络技术有限公司,2012年04月登记成立,法定代表人王安;来源,百度百科“Dcloud” (1)2011年1月,微信1.0发布 (2)2012年,DCloud开始研发小程序技术,推出了HBuilder开发工具 (3)2015年,DCloud商用了小程序技术,命名“流应用”,并将该技术标准捐给工信部,同时推进各家流量巨头接入该标准, 众多开发者用该标准为“流应用”平台提供应用,供用户下载 (4)2015年9月,DCloud推进微信团队开展小程序业务 (5)2016年初,微信团队决定上线微信小程序业务,订制了自己的标准,随后包括手机厂商在内的各大流量巨头, 陆续上线类似微信小程序的业务 (6)2017年1月,微信小程序发布,微信开发工具开发的微信小程序只能在微信上运行, 来源,https://developers.weixin.qq.com/miniprogram/dev/component/text.html (7)2018年8月,DCloud发布uni-app1.0,为开发者抹平各平台的差异,让一套代码在各APP(应用)上运行, 开发工具为HBuilder,js框架为vue,DCloud由标准的提供者转为标准的汇总者 2、uni-app的版本发布 (1)2018年8月,uni-app1.0.0 版本发布, (2)2021年9月,uni-app2.0.0 版本发布, (3)2023年1月,uni-app3.0.0 版本发布, 3、uni-app与weex[wi:ks]、mpvue功能类似,通过单一代码库构建iOS、Android、Web(H5)和小程序等多个平台的应用 (1)2016年4月,阿里巴巴发布跨平台移动开发工具weex,开发者将Weex的SDK嵌入自己的APP,解决了频繁发版和多端研发两大问题 (2)uni-app的vue页面,用“WebKit的”webview渲染,WebKit是一个开源的浏览器引擎 (3)uni-app的nvue页面,用“基于weex改进的”原生渲染引擎渲染,nvue是“native vue”的缩写,意为“原生vue” (4)原生渲染引擎,不是封装别人现成的渲染引擎,而是自己开发的渲染引擎 (5)自悟,浏览器与APP,前者可以浏览所有网站,后者只能浏览一个网站 4、Hybrid,混合开发 (1)Native App,一般指原生应用,是一个完整的应用,依托于操作系统,交互性强,拓展性强,需要用户下载安装使用 (2)Web App,一般指H5应用,使用Web技术(如HTML、CSS和JavaScript)来创建应用程序的用户界面 (3)Hybrid App,一般是指混合型App,带有原生应用外壳的Web应用,是最多的移动端开发方式 A、底层依赖于Native提供的容器(WebView),上层使用html&css&JS做业务开发 B、既有前者良好用户体验的优势,又有后者使用HTML5跨平台开发低成本的优势 5、uni-app与hybrid的区别 (1)uni-app,用于移动端,后出现,负责-前后端分离-的前端 (2)hybrid,用于移动端,先出现,负责-前后端混合-的全部 十二、uniapp跨端框架-教程 1、uni-app的开发规范 (1)页面文件遵循Vue单文件组件(SFC)规范,即每个页面是一个.vue文件 (2)组件标签靠近小程序规范, (3)接口能力靠近小程序规范,但需将前缀wx、my等替换为uni (4)数据绑定及事件处理同Vue.js规范,同时补充了应用生命周期及页面的生命周期 (5)如需兼容app-nvue平台,建议使用flex布局进行开发 (6)uni-app分编译器和运行时(runtime),都内置在HBuilderX中,编译器在开发环境编译代码并生成输出物, 在各终端上,各运行时(runtime)解析各输出物 2、uni-app的编译器 (1)编译器,运行在电脑开发环境 (2)开发者按uni-app规范编写代码,由编译器将开发者的统一代码编译生成每个平台支持的特有代码 在web平台,将.vue文件编译为js代码 在微信小程序平台,编译器将.vue文件拆分生成wxml、wxss、js等代码 在app平台,将.vue文件编译为js代码 在Android平台,将.uts文件编译为kotlin代码 在iOS平台,将.uts文件编译为swift代码 (3)uni-app项目根据所依赖的Vue版本不同,编译器的实现也不同 vue2版,基于webpack实现 vue3版,基于Vite实现,性能更快 (4)支持条件编译 (5)编译到任意平台时, static目录下满足编译条件的文件,会直接复制到最终的打包目录 非static目录下的文件(vue、js、css等)只有被引用时,才会被打包编译 (6).uts,意为统一类型脚本,全称为“uni type script” 3、uni-app的运行时(runtime) (1)runtime,运行在终端上,动态处理数据绑定、事件代理,保证Vue和平台宿主数据的一致性,这是一个比较庞大的工程 在小程序端,uni-app的runtime,主要是一个小程序版的vue runtime,页面路由、组件、api等方面基本都是转义 在web端,uni-app的runtime相比普通的vue项目,多了一套ui库、页面路由框架、和uni对象(即常见API封装) 在App端,uni-app的runtime更复杂,DCloud也有一套小程序引擎,打包app时将开发者的代码和DCloud的小程序打包成了apk或ipa (2)uni-app的runtime包括3部分,基础框架、组件、API 4、uni-app处理各终端的逻辑层和视图层分离 (1)在web平台,逻辑层(js)和视图层(html、css),都运行在统一的webview里 (2)在小程序和app端,逻辑层和视图层被分离了,原因为基于webview的app因js运算和界面渲染抢资源导致卡顿而性能不佳 逻辑层都独立成单独的js引擎,不支持浏览器专用的window、dom等API, 视图层仍然是webview,能视图层操作window、dom 5、uni-app的工程,一个uni-app工程,就是一个“Vue项目”(非常重要),可以通过HBuilderX或cli快速创建 6、页面 (1)一个页面就是一个符合Vue SFC规范的.vue文件或.nvue文件 (2)页面保存在工程根目录下的pages目录下 (3)每次新建页面,均需在工程根目录下的pages.json中配置pages列表 (4)删除页面时,需删除.vue文件或.nvue文件,删除pages.json中pages列表项中的配置 (5)uni-app会将pages.json中pages配置项中的第一个页面,作为当前工程的首页(启动页) (6)uni-app页面除支持Vue组件生命周期外还支持页面生命周期函数onInit、onLoad、onShow、onReady、onHide、onUnload、onResize、......... (7)uni-app组件支持的生命周期,与vue标准组件的生命周期相同beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed (8)页面调用接口 getApp,函数用于获取当前应用实例,一般用于获取全局数据 const app = getApp() console.log(app.globalData) getCurrentPages,函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面 const page = getCurrentPages() page.$getAppWebview(),获取当前页面的webview对象实例 page.route,获取当前页面的路由 $getAppWebview(),在getCurrentPages()获得的页面里内置了一个方法$getAppWebview(),获取当前页面的webview对象实例 var pages = getCurrentPages(); var page = pages[pages.length - 1]; var currentWebview = page.$getAppWebview(); console.log(currentWebview.id);//获得当前webview的id console.log(currentWebview.isVisible());//查询当前webview是否可见 (9)页面通讯 uni.$emit(eventName,OBJECT),触发全局的自定义事件,附加参数都会传给监听器回调 uni.$on(eventName,callback),监听全局的自定义事件,事件可以由 uni.$emit 触发,回调函数会接收所有传入事件触发函数的额外参数 uni.$once(eventName,callback),监听全局的自定义事件,事件可以由 uni.$emit 触发,但是只触发一次,在第一次触发之后移除监听器 uni.$off([eventName,callback]),移除全局自定义事件监听器 (10)uni-app框架统一管理页面路由,开发者需要在pages.json里配置每个路由页面的路径及页面样式,使用navigator组件跳转、调用API跳转 (11)框架以栈的形式管理当前所有页面 (12)支持在template模板中嵌套<template/>和<block/> (13)nvue开发与vue开发的常见区别 7、组件 (1)uni-app组件 视图容器 基础内容 表单组件 路由与页面跳转 媒体组件 (2)Vue组件 (3)NVUE组件 (4)小程序组件 (5)扩展组件(uni-ui) 8、引用组件 (1)传统vue项目开发,引用组件需要导入-注册-使用三个步骤,如下: <template> <view> <!-- 3.使用组件 --> <uni-rate text="1"></uni-rate> </view> </template> <script> //1. 导入组件 import uniRate from '@/components/uni-rate/uni-rate.vue'; export default { components: { uniRate } //2. 注册组件 } </script> (2)Vue 3.x增加了script setup特性,将三步优化为两步,无需注册步骤,更为简洁: <template> <view> <!-- 2.使用组件 --> <uni-rate text="1"></uni-rate> </view> </template> <script setup> //1. 导入组件 import uniRate from '@/components/uni-rate/uni-rate.vue'; </script> (3)uni-app的easycom机制,将组件引用进一步优化,开发者只管使用,无需考虑导入和注册,更为高效: 在 uni-app 项目中,页面引用组件和组件引用组件的方式都是一样的(可以理解为:页面是一种特殊的组件),均支持通过 easycom 方式直接引用。 <template> <view> <!-- 1.使用组件 --> <uni-rate text="1"></uni-rate> </view> </template> <script> </script> 9、引用JS (1)绝对路径,@指向项目根目录,在cli项目中@指向src目录 import add from '@/common/add.js'; (2)相对路径 import add from '../../common/add.js'; (3)js中引入npm包 import package from 'packageName' const package = require('packageName') 10、引用CSS <style> @import "../../common/uni.css"; .uni-card { box-shadow: none; } </style> 11、引用静态资源,https://uniapp.dcloud.net.cn/tutorial/page-static-assets.html (1)#模板内引入静态资源 template内引入静态资源,如image、video等标签的src属性时,可以使用相对路径或者绝对路径 <!-- 绝对路径,/static指根目录下的static目录,在cli项目中/static指src目录下的static目录 --> <image class="logo" src="/static/logo.png"></image> <image class="logo" src="@/static/logo.png"></image> <!-- 相对路径 --> <image class="logo" src="../../static/logo.png"></image> (2)css 引入静态资源 css文件或style标签内引入css文件时(scss、less 文件同理),可以使用相对路径或绝对路径 /* 绝对路径 */ @import url('/common/uni.css'); @import url('@/common/uni.css'); /* 相对路径 */ @import url('../../common/uni.css'); 12、JS语法 (1)uni-app的js API由标准ES的js API和uni扩展API这两部分组成 标准ECMAScript的js仅是最基础的js 浏览器扩展了window、document、navigator等对象 小程序扩展了各种wx.xx、my.xx、swan.xx的API node扩展了fs等模块 uni-app扩展了uni对象,并且API命名与小程序保持兼容 (2)标准js和浏览器js的区别 h5端,JS运行于浏览器中 非h5端(包含小程序和App),Android平台JS运行在v8引擎中,iOS平台JS运行在iOS自带的jscore引擎中,都没有运行在浏览器或webview里 非H5端,虽然不支持window、document、navigator等浏览器的js API,但也支持标准ECMAScript (3)支持绝大部分ES6 API的同时,也支持了ES7的 await/async 13、CSS语法 (1)uni-app的css与web的css基本一致 (2)nvue页面里的样式比web页面里的样式限制更多 (3)支持的通用css单位包括px、rpx 14、vue语法,仅以“组合式API”为例 (1)目前uni-app基于Vue2.6,组合式API由@vue/composition-api支持,setup由unplugin-vue2-script-setup支持 (2)在main.js或main.ts文件内增加安装@vue/composition-api插件 (3)在每个nvue页面安装@vue/composition-api插件 15、vue3组合式API(Composition API),按照逻辑关注点,对部分代码进行分组 注,来自于文章10,https://www.cnblogs.com/gushixianqiancheng/p/13392540.html (1)vue2中,通过配置项(data、computed、methods、watch)将相关逻辑拆散,不便于组件阅读和维护 (2)vue3中,通过组合式API(setup、ref、reactive、watchEffect、watch、computed、toRefs、生命周期的hooks),将相关逻辑写在一起,便于组件阅读和维护 (3)setup函数接受两个参数:(props、context) props参数是响应式数据,解构props的操作必须通过toRefs完成,toRefs将对象的多个属性变成响应式数据,如var {title} = toRefs(props) context参数不是响应式数据,可以直接解构,包含attrs、slots、emit,其中attrs是组件的props配置中没有声明的属性 (4)setup执行时,组件实例尚未被创建,this修改成undefined (5)setup之ref和reactive的区别 ref定义基本类型数据,使用Object.defineProperty实现数据代理,使用refData.value.name获取数据(template模板中不需要.value) reactive定义引用类型数据,使用Proxy实现数据代理,使用reactData.username获取数据 (6)setup通过ref、reactive、computed生成组件所需值;通过方法,改变组件值、全局值 以下,组合式API之computed,来源,https://blog.csdn.net/ct5211314/article/details/125874348 <template> <div> <div>姓:<input type="text" v-model="per.surname"></div> <div>名:<input type="text" v-model="per.name"></div> <div>姓名:<input type="text" v-model="per.fullName"></div> </div> </template> <script> import { computed, reactive } from 'vue' export default { setup(){ let per = reactive({ surname:'勇敢', name:'小陈' }) per.fullName = computed(()=>{ return per.surname+'~'+per.name }) return{ per } } } </script> 以下,组合式API之watchEffect,来源,https://blog.csdn.net/ZYS10000/article/details/124535467 watchEffect,是一个帧听器,是一个副作用函数,它会监听引用数据类型的所有属性,不需要具体到某个属性,一旦运行就会立即监听,组件卸载的时候会停止监听。 import { reactive, watchEffect } from 'vue'; export default { setup(){ let obj = reactive({ name:'zs' }); watchEffect(() => { console.log('name:',obj.name) }) return { obj } } } 16、ts语法 <script lang="ts"> //这里编写ts代码 let s:string = "123" console.log(s) </script> 17、uts语法 (1)uts,全称uni type script,是一门跨平台的、高性能的、强类型的现代编程语言, (2)uts采用了与ts基本一致的语法规范,支持绝大部分ES6 API (3)uts可以被编译为不同平台的编程语言 web平台,编译为JavaScript Android平台,编译为Kotlin iOS平台,编译Swift 十三、uniapp跨端框架-全局文件 1、pages.json 页面路由,对uni-app进行全局配置,决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等 { "pages": [{ "path": "pages/component/index", "style": { "navigationBarTitleText": "组件" } }, { "path": "pages/API/index", "style": { "navigationBarTitleText": "接口" } }, { "path": "pages/component/view/index", "style": { "navigationBarTitleText": "view" } }], "condition": { //模式配置,仅开发期间生效 "current": 0, //当前激活的模式(list 的索引项) "list": [{ "name": "test", //模式名称 "path": "pages/component/view/index" //启动页面,必选 }] }, "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "演示", "navigationBarBackgroundColor": "#F8F8F8", "backgroundColor": "#F8F8F8", "usingComponents":{ "collapse-tree-item":"/components/collapse-tree-item" }, "renderingMode": "seperated", //仅微信小程序,webrtc 无法正常时尝试强制关闭同层渲染 "pageOrientation": "portrait", //横屏配置,全局屏幕旋转设置(仅 APP/微信/QQ小程序),支持 auto / portrait / landscape "rpxCalcMaxDeviceWidth": 960, "rpxCalcBaseDeviceWidth": 375, "rpxCalcIncludeWidth": 750 }, "tabBar": { "color": "#7A7E83", "selectedColor": "#3cc51f", "borderStyle": "black", "backgroundColor": "#ffffff", "height": "50px", "fontSize": "10px", "iconWidth": "24px", "spacing": "3px", "iconfontSrc":"static/iconfont.ttf", //app tabbar 字体.ttf文件路径 app 3.4.4+ "list": [{ "pagePath": "pages/component/index", "iconPath": "static/image/icon_component.png", "selectedIconPath": "static/image/icon_component_HL.png", "text": "组件", "iconfont": { //优先级高于 iconPath,该属性依赖 tabbar 根节点的 iconfontSrc "text": "\ue102", "selectedText": "\ue103", "fontSize": "17px", "color": "#000000", "selectedColor": "#0000ff" } }, { "pagePath": "pages/API/index", "iconPath": "static/image/icon_API.png", "selectedIconPath": "static/image/icon_API_HL.png", "text": "接口" }], "midButton": { "width": "80px", "height": "50px", "text": "文字", "iconPath": "static/image/midButton_iconPath.png", "iconWidth": "24px", "backgroundImage": "static/image/midButton_backgroundImage.png" } }, "easycom": { "autoscan": true, //是否自动扫描组件 "custom": {//自定义扫描规则 "^uni-(.*)": "@/components/uni-$1.vue" } }, "topWindow": { "path": "responsive/top-window.vue", "style": { "height": "44px" } }, "leftWindow": { "path": "responsive/left-window.vue", "style": { "width": "300px" } }, "rightWindow": { "path": "responsive/right-window.vue", "style": { "width": "300px" }, "matchMedia": { "minWidth": 768 } } } 2、manifest.json配置,文件是应用的配置文件,用于指定应用的名称、图标、权限等 { "quickapp-webview": {//快应用通用配置 "icon": "/static/logo.png", "package": "com.example.demo", "versionName": "1.0.0", "versionCode": 100 }, "quickapp-webview-union": {//快应用联盟,目前仅支持 vivo、oppo "minPlatformVersion": 1063 //最小平台支持 }, "quickapp-webview-huawei": {//快应用华为 "minPlatformVersion": 1070 //最小平台支持 } } 3、package.json扩展配置 { /** * package.json其它原有配置 * 拷贝代码后请去掉注释! */ "uni-app": {//扩展配置 "scripts": { "custom-platform": { //自定义编译平台配置,可通过cli方式调用 "title":"自定义扩展名称", //在HBuilderX中会显示在 运行/发行 菜单中 "browser":"", //运行到的目标浏览器,仅当UNI_PLATFORM为h5时有效 "env": {//环境变量 "UNI_PLATFORM": "", //基准平台 "MY_TEST": "", //... 其他自定义环境变量 }, "define": { //自定义条件编译 "CUSTOM-CONST": true //自定义条件编译常量,建议为大写 } } } } } 4、vue.config.js,是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,一般用于配置webpack等编译选项 const path = require('path') const webpack = require('webpack') const CopyWebpackPlugin = require('copy-webpack-plugin') //最新版本copy-webpack-plugin插件暂不兼容,推荐v5.0.0 module.exports = { configureWebpack: { plugins: [ new CopyWebpackPlugin([ { from: path.join(__dirname, 'src/images'), to: path.join(__dirname, 'dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env.UNI_PLATFORM, 'images') } ]) ] }, chainWebpack: config => { config .plugin('define') .tap(args => { args[0]['process.env'].VUE_APP_TEST = '"test"' return args }) } } 5、vite.config.js,是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,一般用于配置vite的编译选项, 必须引用 '@dcloudio/vite-plugin-uni' 并且添加到 plugins 中 示例一、自定义静态资源目录 import path from 'path'; import fs from 'fs-extra'; import { defineConfig } from 'vite'; import uni from '@dcloudio/vite-plugin-uni'; function copyFile() { return { enforce: 'post', async writeBundle() { await fs.copy( path.resolve(__dirname, 'images'), path.join( __dirname, 'unpackage/dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env.UNI_PLATFORM, 'images' ) ); }, }; } export default defineConfig({ plugins: [uni(), copyFile()], }); 示例二、注入全局依赖 //示例从插件市场下载 mp-storage import path from 'path'; import { defineConfig } from 'vite'; import uni from '@dcloudio/vite-plugin-uni'; import inject from '@rollup/plugin-inject'; const mpStoragePath = path.resolve(__dirname, './js_sdk/mp-storage/mp-storage'); export default defineConfig({ plugins: [ uni(), inject({ localStorage: [mpStoragePath, 'localStorage'], 'window.localStorage': [mpStoragePath, 'localStorage'], }), ], define: { 'process.env.VUE_APP_TEST': JSON.stringify('test'), }, }); 示例三、配置环境变量 import { defineConfig } from 'vite'; import uni from '@dcloudio/vite-plugin-uni'; export default defineConfig({ plugins: [uni()], define: { 'process.env.VUE_APP_TEST': JSON.stringify('test'), }, }); 6、uni.scss文件的用途是为了方便整体控制应用的风格。比如按钮颜色、边框风格,uni.scss文件里预置了一批scss变量预置 <style lang="scss"> </style> 以下是uni.scss的相关变量 $uni-color-primary: #007aff; $uni-color-success: #4cd964; $uni-color-warning: #f0ad4e; $uni-color-error: #dd524d; 7、App.vue是uni-app的主组件,所有页面都是在App.vue下进行切换的,是页面的入口文件 (1)App.vue本身不是页面,这里不能编写视图元素,也就是没有<template> (2)这个文件的作用包括:调用应用生命周期函数、配置全局样式、配置全局的存储globalData (3)应用生命周期仅可在App.vue中监听,在页面监听无效 (4)js中操作globalData的方式如下:getApp().globalData.text = 'test' (5)示例代码 <script> //只能在App.vue里监听应用的生命周期 export default { globalData: { text: 'text' } onLaunch: function() { console.log('App Launch') }, onShow: function() { console.log('App Show') }, onHide: function() { console.log('App Hide') } } </script> 8、main.js是uni-app的入口文件,主要作用是初始化vue实例、定义全局组件、使用需要的插件如vuex (1)vue2代码示例 import Vue from 'vue' import App from './App' import pageHead from './components/page-head.vue' //全局引用 page-head 组件 Vue.config.productionTip = false Vue.component('page-head', pageHead) //全局注册 page-head 组件,每个页面将可以直接使用该组件 App.mpType = 'app' const app = new Vue({ ...App }) app.$mount() //挂载 Vue 实例 (2)vue3代码示例 import App from './App' import { createSSRApp } from 'vue' export function createApp() { const app = createSSRApp(App) return { app } } 十四、postcss.config.js 来源,https://www.fke6.com/html/110797.html 来源,https://blog.csdn.net/Jensen_Yao/article/details/103203490 注、通过gulp、webpack、grunt等构建工具来使用,用于配置PostCSS的插件和选项,处理CSS 1、示例一,插件排序与插件参数 module.exports = { plugins: [//插件排序 require('postcss-import'), require('postcss-url')({//插件参数 url: 'inline' }), require('precss'), require('autoprefixer')({//插件参数 browsers: ['last 2 versions'] }) ] } 2、示例二,px转rem,rootValue*10=设计稿的宽 module.exports = () => ({ plugins: [ require('autoprefixer')(), //require('postcss-px2rem')({ remUnit: 75 }) require('postcss-pxtorem')({ rootValue: 37.5, //对应设计图宽度375px propList: ['*'], //将哪些属性的px值转换,['*']将所有属性的px值转换,['*', '!border*']含border的属性的px值不转换,其余的都转换 }) ] }); 3、示例三,px转vw module.exports = { plugins: { autoprefixer: {}, 'postcss-px-to-viewport': { exclude: undefined, //忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件 fontViewportUnit: 'vw', //字体使用的视口单位 include: undefined, //如果设置了include,那将只有匹配到的文件才会被转换 landscape: false, //是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape) landscapeUnit: 'vw', //横屏时使用的单位 landscapeWidth: 1920, //横屏时使用的视口宽度 mediaQuery: false, //媒体查询里的单位`px`是否需要转换,false为默认值 minPixelValue: 1, //设置最小的转换数值,只有大于`1px`的值转换为视窗单位 propList: ['*'], //能转化为vw的属性列表 replace: true, //是否直接更换属性值,而不添加备用属性 selectorBlackList: ['p', '.hairlines'], //需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位 unitPrecision: 5, //转换后保留的小数位数,precision精确 unitToConvert: 'px', //需要转换的单位,默认为"px" viewportWidth: 375, //设计稿的视口宽度,375px=100vw viewportHeight: 1334, //视窗的高度,1334px=100vh viewportUnit: 'vw', //指定转换后的视窗单位,建议使用vw }, 'postcss-viewport-units': { //排除会产生警告的部份 filterRule: rule => rule.nodes.findIndex(i => i.prop === 'content') === -1 }, cssnano: {//集成了部分PostCSS插件,用false禁用其中的某个插件,nano毫微 preset: 'advanced', //预设: 高级(转换) autoprefixer: false, //禁用autoprefixer,和上面的autoprefixer: {}具有相同效果 'postcss-zindex': false } } }