微信小程序开发
<h3>面试题</h3><p><strong>1 项目结构的文件类型:</strong></p>
<ul>
<li><code>WXML</code>(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。内部主要是微信自己定义的一套组件</li>
<li><code>WXSS</code> (WeiXin Style Sheets)是一套样式语言,用于描述 <code>WXML</code> 的组件样式</li>
<li><code>js</code> 逻辑处理,网络请求</li>
<li><code>json</code> 小程序设置,如页面注册,页面标题及<code>tabBar</code></li>
</ul>
<p><strong>2 微信小程序原理:</strong></p>
<p><strong>微信小程序采用 <code>JavaScript</code>、<code>WXML</code>、<code>WXSS</code> 三种技术进行开发,本质就是一个单页面应用,所有的页面渲染和事件处理,都在一个页面内进行,但又可以通过微信客户端调用原生的各种接口</strong></p>
<p>微信的架构,是数据驱动的架构模式,它的 <code>UI</code> 和数据是分离的,所有的页面更新,都需要通过对数据的更改来实现;</p>
<p>小程序分为两个部分 <code>webview</code> 和 <code>appService</code> 。其中 <code>webview</code> 主要用来展现 <code>UI</code>,<code>appService</code> 有来处理业务逻辑、数据及接口调用。它们在两个进程中运行,<strong>通过系统层 <code>JSBridge</code> 实现通信</strong>,实现 <code>UI</code> 的渲染、事件的处理;</p>
<p>小程序逻辑和UI执行在2个独立的Webview里面,这个是跟当前流行的react,agular,vue本质的差别;</p>
<p>小程序开发框架的目标是通过尽可能简单高效的方式让开发者可以在微信中开发具有原生app体验的服务,<strong>JSBridge下架起上层开发与Native(系统层)的桥梁,使得小程序可通过API使用原生的功能,且部分组件为原生组件实现,从而有良好体验</strong>:</p>
<p><img src="https://img2020.cnblogs.com/blog/1234412/202005/1234412-20200507112509976-1181080590.png"></p>
<h3><img src="https://img2020.cnblogs.com/blog/1234412/202005/1234412-20200507114914990-1803746328.png"></h3>
<h3 id="appservice">AppService</h3>
<p>可以理解AppService即一个简单的页面,主要功能是负责逻辑处理部分的执行,底层提供一个WAService.js的文件来提供各种api接口,主要是以下几个部分: </p>
<p>1、日志组件Reporter封装 ;<br>2、wx对象下面的api方法 ;<br>3、全局的App,Page,getApp,getCurrentPages等全局方法 ;<br>4、还有就是对AMD模块规范的实现;</p>
<p><strong>3 小程序的双向绑定和vue区别:</strong></p>
<p>小程序直接 <code>this.data</code> 修改属性是不能更改视图,必须调用:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setData({
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里设置</span>
})</pre>
</div>
<p><strong>4 wxss和css有哪些不一样的地方:</strong></p>
<p>WXSS 和 CSS 类似,不过在 CSS 的基础上做了一些补充和修改</p>
<p><strong>尺寸单位 rpx</strong>:rpx 是响应式像素,可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx,如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素</p>
<p>使用 @import 标识符来导入外联样式。@import 后跟需要导入的外联样式表的相对路径,用;表示语句结束:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">* index.wxss *</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@import </span>'./base.wxss'<span style="color: rgba(0, 0, 0, 1)">;
.container{
color: red;
}</span></pre>
</div>
<p><strong>5 小程序传递数据的方法:</strong></p>
<p>使用全局变量实现数据传递,在 app.js 文件中定义全局变量 globalData, 将需要存储的信息存放在里面:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> app.js</span>
<span style="color: rgba(0, 0, 0, 1)">
App({
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 全局变量</span>
<span style="color: rgba(0, 0, 0, 1)">globalData: {
userInfo: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
}
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 直接使用 getApp() 拿到存储的信息</span></pre>
</div>
<p>使用 wx.navigateTo 与 wx.redirectTo 的时候,可以将部分数据放在 url 里面,并在新页面 onLoad 的时候初始化</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">pageA.js</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Navigate</span>
<span style="color: rgba(0, 0, 0, 1)">wx.navigateTo({
url: </span>'../pageD/pageD?name=raymond&gender=male'<span style="color: rgba(0, 0, 0, 1)">,
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Redirect</span>
<span style="color: rgba(0, 0, 0, 1)">wx.redirectTo({
url: </span>'../pageD/pageD?name=raymond&gender=male'<span style="color: rgba(0, 0, 0, 1)">,
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> pageB.js</span>
<span style="color: rgba(0, 0, 0, 1)">...
Page({
onLoad: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(option){
console.log(option.name </span>+ 'is' +<span style="color: rgba(0, 0, 0, 1)"> option.gender)
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setData({
option: option
})
}
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 注意:</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> wx.navigateTo 和 wx.redirectTo 不允许跳转到 tab 所包含的页面</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> onLoad 只执行一次</span></pre>
</div>
<p>使用本地缓存 Storage 相关</p>
<p><strong>6 小程序的生命周期</strong></p>
<p>onLoad() 页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数;<br>onShow() 页面显示/切入前台时触发;<br>onReady() 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互;<br>onHide() 页面隐藏/切入后台时触发。 如 navigateTo 或底部 tab 切换到其他页面,小程序切入后台等;<br>onUnload() 页面卸载时触发。如 redirectTo 或 navigateBack 到其他页面时;</p>
<p>微信小程序生命周期分“应用生命周期”和“页面生命周期”。<br>应用生命周期含onLaunch, onShow, onHide状态,onLaunch, onShow可获取打开小程序时的相关参数path, query, scene, shareTicket, referrerInfo,注册为App({}),一个小程序只有一个App({})。<br>页面生命周期含onLoad, onShow, onHide, onReady, onUnload,onLoad可获取其他页面打开当前页面时所所调用的query参数,注册为Page({}),每个页面有且必须有一个Page({})。</p>
<p><strong>7 封装小程序请求</strong></p>
<div class="cnblogs_code">
<pre>const baseUrl = 'https://api.it120.cc'<span style="color: rgba(0, 0, 0, 1)">;
const http </span>= ({ url = '', param = {}, ...other } = {}) =><span style="color: rgba(0, 0, 0, 1)"> {
wx.showLoading({
title: </span>'请求中,请耐心等待..'<span style="color: rgba(0, 0, 0, 1)">
});
let timeStart </span>=<span style="color: rgba(0, 0, 0, 1)"> Date.now();
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Promise((resolve, reject) =><span style="color: rgba(0, 0, 0, 1)"> {
wx.request({
url: getUrl(url),
data: param,
header: {
</span>'content-type': 'application/json' <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 默认值 ,另一种是 "content-type": "application/x-www-form-urlencoded"</span>
<span style="color: rgba(0, 0, 0, 1)"> },
...other,
complete: (res) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
wx.hideLoading();
console.log(`耗时${Date.now() </span>-<span style="color: rgba(0, 0, 0, 1)"> timeStart}`);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (res.statusCode >= 200 && res.statusCode < 300<span style="color: rgba(0, 0, 0, 1)">) {
resolve(res.data)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
reject(res)
}
}
})
})
}
const getUrl </span>= (url) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (url.indexOf('://') == -1<span style="color: rgba(0, 0, 0, 1)">) {
url </span>= baseUrl +<span style="color: rgba(0, 0, 0, 1)"> url;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> url
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> get方法</span>
const _get = (url, param = {}) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> http({
url,
param
})
}
const _post </span>= (url, param = {}) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> http({
url,
param,
method: </span>'post'<span style="color: rgba(0, 0, 0, 1)">
})
}
const _put </span>= (url, param = {}) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> http({
url,
param,
method: </span>'put'<span style="color: rgba(0, 0, 0, 1)">
})
}
const _delete </span>= (url, param = {}) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> http({
url,
param,
method: </span>'put'<span style="color: rgba(0, 0, 0, 1)">
})
}
module.exports </span>=<span style="color: rgba(0, 0, 0, 1)"> {
baseUrl,
_get,
_post,
_put,
_delete
}</span></pre>
</div>
<p>使用:</p>
<div class="cnblogs_code">
<pre>const api = require('../../utils/api.js'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 单个请求</span>
api.get('list').then(res =><span style="color: rgba(0, 0, 0, 1)"> {
console.log(res)
}).</span><span style="color: rgba(0, 0, 255, 1)">catch</span>(e =><span style="color: rgba(0, 0, 0, 1)"> {
console.log(e)
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 一个页面多个请求</span>
<span style="color: rgba(0, 0, 0, 1)">Promise.all([
api.get(</span>'list'<span style="color: rgba(0, 0, 0, 1)">),
api.get(`detail</span>/${id}`)
]).then(result =><span style="color: rgba(0, 0, 0, 1)"> {
console.log(result)
}).</span><span style="color: rgba(0, 0, 255, 1)">catch</span>(e =><span style="color: rgba(0, 0, 0, 1)"> {
console.log(e)
})</span></pre>
</div>
<p>登录</p>
<p>小程序并没有登录界面,使用的是 wx.login 。 wx.login 会获取到一个 code,拿着该 code 去请求我们的后台会最后返回一个token到小程序这边,保存这个值为 token 每次请求的时候带上这个值。<br>一般还需要把用户的信息带上比如用户微信昵称,微信头像等,这时候就需要使用 wx.getUserInfo ,这里涉及到一个用户授权的问题<br>我们的项目不可能只有小程序,相应的微信公众平台可能还有相应的App,我们需要把账号系统打通,让用户在我们的项目中的账户是同一个。这就需要用到微信开放平台提供的 UnionID 。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">app.js</span>
<span style="color: rgba(0, 0, 0, 1)">App({
onLaunch: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
console.log(</span>'App onLaunch'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> that = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取商城名称</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.request({
url: </span>'https://api.it120.cc/'+ that.globalData.subDomain +'/config/get-value'<span style="color: rgba(0, 0, 0, 1)">,
data: {
key: </span>'mallName'<span style="color: rgba(0, 0, 0, 1)">
},
success: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(res) {
wx.setStorageSync(</span>'mallName'<span style="color: rgba(0, 0, 0, 1)">, res.data.data.value);
}
})
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.login();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.getUserInfo();
},
login : </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> that = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> token =<span style="color: rgba(0, 0, 0, 1)"> that.globalData.token;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果有token</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (token) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 检查token是否有效</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.request({
url: </span>'https://api.it120.cc/' + that.globalData.subDomain + '/user/check-token'<span style="color: rgba(0, 0, 0, 1)">,
data: {
token: token
},
success: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (res) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果token失效了</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (res.data.code != 0<span style="color: rgba(0, 0, 0, 1)">) {
that.globalData.token </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
that.login(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 重新登陆</span>
<span style="color: rgba(0, 0, 0, 1)"> }
}
})
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 【1】调用微信自带登陆</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.login({
success: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (res) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 【2】 拿到code去访问我们的后台换取其他信息</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.request({
url: </span>'https://api.it120.cc/'+ that.globalData.subDomain +'/user/wxapp/login'<span style="color: rgba(0, 0, 0, 1)">,
data: {
code: res.code
},
success: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(res) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果说这个code失效的</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (res.data.code == 10000<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 去注册</span>
<span style="color: rgba(0, 0, 0, 1)"> that.registerUser();
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果返回失败了</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (res.data.code != 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 登录错误 </span>
<span style="color: rgba(0, 0, 0, 1)"> wx.hideLoading();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 提示无法登陆</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.showModal({
title: </span>'提示'<span style="color: rgba(0, 0, 0, 1)">,
content: </span>'无法登录,请重试'<span style="color: rgba(0, 0, 0, 1)">,
showCancel:</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
})
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 【3】 如果成功后设置token到本地</span>
that.globalData.token =<span style="color: rgba(0, 0, 0, 1)"> res.data.data.token;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 保存用户信息</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.setStorage({
key: </span>'token'<span style="color: rgba(0, 0, 0, 1)">,
data:res.data.data.token
})
}
})
}
})
},
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 注册?? [这个看需求]</span>
registerUser: <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> that = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
wx.login({
success: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (res) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> code = res.code; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 微信登录接口返回的 code 参数,下面注册接口需要用到</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.getUserInfo({
success: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (res) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> iv =<span style="color: rgba(0, 0, 0, 1)"> res.iv;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> encryptedData =<span style="color: rgba(0, 0, 0, 1)"> res.encryptedData;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 下面开始调用注册接口</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.request({
url: </span>'https://api.it120.cc/' + that.globalData.subDomain +'/user/wxapp/register/complex'<span style="color: rgba(0, 0, 0, 1)">,
data: {code:code,encryptedData:encryptedData,iv:iv}, </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置请求的 参数</span>
success: (res) =><span style="color: rgba(0, 0, 0, 1)">{
wx.hideLoading();
that.login();
}
})
}
})
}
})
},
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取用户信息</span>
getUserInfo:<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
wx.getUserInfo({
success:(data) </span>=><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.globalData.userInfo =<span style="color: rgba(0, 0, 0, 1)"> data.userInfo;
wx.setStorage({
key: </span>'userInfo'<span style="color: rgba(0, 0, 0, 1)">,
data:data.userInfo
})
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.globalData.userInfo;
}
})
},
globalData:{
userInfo:</span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
subDomain:</span>"34vu54u7vuiuvc546d"<span style="color: rgba(0, 0, 0, 1)">,
token: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
}
})</span></pre>
</div>
<p>授权</p>
<p><img src="https://img2020.cnblogs.com/blog/1234412/202004/1234412-20200419092622159-1153434342.png"></p>
<p> </p>
<div class="cnblogs_code">
<pre>getUserInfo: <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 先调用wx.getSetting 获取用户权限设置</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.getSetting({
success(res) {
console.log(</span>'1'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!res.authSetting['scope.userInfo'<span style="color: rgba(0, 0, 0, 1)">]) {
wx.authorize({
scope: </span>'scope.userInfo'<span style="color: rgba(0, 0, 0, 1)">,
success() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 用户已经同意小程序使用录音功能,后续调用 wx.getUserInfo接口不会弹窗询问</span>
<span style="color: rgba(0, 0, 0, 1)"> wx.getUserInfo({
success: (data) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.globalData.userInfo =<span style="color: rgba(0, 0, 0, 1)"> data.userInfo;
wx.setStorage({
key: </span>'userInfo'<span style="color: rgba(0, 0, 0, 1)">,
data: data.userInfo
})
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.globalData.userInfo;
}
})
}
})
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>2<span style="color: rgba(0, 0, 0, 1)">);
}
}
})
},</span></pre>
</div>
<p><strong>8 小程序优劣势</strong></p>
<p>优点:</p>
<p>即用即走,不用安装,省流量,省安装时间,不占用桌面;<br>依托微信流量,天生推广传播优势;<br>开发成本比 App 低;</p>
<p> 缺点:</p>
<p>入口相对传统 App 要深很多;<br>限制较多,页面大小不能超过2M。不能打开超过10个层级的页面;</p>
<p><strong>9 微信下小程序公众号等如何确定用户的唯一性</strong></p>
<p>如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 unionid 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 unionid 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid 是相同的</p>
<p><strong>10 如何实现下拉刷新</strong></p>
<p>首先在全局 config 中的 window 配置 enablePullDownRefresh;<br>在 Page 中定义 onPullDownRefresh 钩子函数,到达下拉刷新条件后,该钩子函数执行,发起请求方法;<br>请求返回后,调用 wx.stopPullDownRefresh 停止下拉刷新;</p>
<p><strong>11 bindtap和catchtap的区别</strong></p>
<p>相同点:首先他们都是作为点击事件函数,就是点击时触发;</p>
<p>不同点:他们的不同点主要是bindtap是不会阻止冒泡事件的,catchtap是阻值冒泡的;</p>
<p><strong>12 wx.navigateTo(), wx.redirectTo(), wx.switchTab(), wx.navigateBack(), wx.reLaunch()的区别</strong></p>
<p>wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面;<br>wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面;<br>wx.switchTab():跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面;<br>wx.navigateBack():关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层;<br>wx.reLaunch():关闭所有页面,打开到应用内的某个页面;</p>
<p><strong>13 小程序的双线程模式</strong></p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1234412/202004/1234412-20200419093722693-2103075265.png"></strong></p>
<h3> 14 为什么小程序最多允许打开5个层级的页面?</h3>
<div>小程序的UI视图和逻辑处理是用多个webview实现的,逻辑处理的JS代码全部加载到一个Webview里面,称之为AppService,整个小程序只有一个,并且整个生命周期常驻内存,而所有的视图(wxml和wxss)都是单独的Webview来承载,称之为AppView。</div>
<div>所以一个小程序打开至少就会有2个webview进程,正式因为每个视图都是一个独立的webview进程,考虑到性能消耗,小程序不允许打开超过5个层级的页面,当然同是也是为了体验更好。</div>
<p>1 上述的渲染层上面运行这wxml文件已经wxss文件,渲染层使用是的webview线程进行渲染(一个程序会有多个页面,也就会有多个view线程进行运作)</p>
<p>2 js文件是运行在逻辑层,逻辑层的js是通过jscore进行运行的。</p>
<p> </p>
<h3>开发</h3>
<p>1 用微信开发者工具初始化项目;</p>
<p>2 初始化后文件夹里包含以下文件:</p>
<p><img src="https://img2018.cnblogs.com/common/1234412/202001/1234412-20200114141103317-49105405.png"></p>
<p>小程序会读取app.js、app.json、app.wxss这三个文件初始化实例。</p>
<p>app.js是小程序的初始化脚本,可以在这个文件中监听小程序的生命周期,定义全局变量和调用API等。使用App()来注册一个小程序,必须在<code>app.js</code>中注册,且不能注册多个</p>
<div class="cnblogs_code">
<pre>App({<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如下为小程序的生命周期</span>
onLaunch: function() { },<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听初始化</span>
onShow: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听显示(进入前台)</span>
onHide: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听隐藏(进入后台:按home离开微信)</span>
onError: function(msg) {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听错误
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如下为自定义的全局方法和全局变量</span>
<span style="color: rgba(0, 0, 0, 1)">globalFun:function(){},
globalData: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">I am global data</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
})</span></pre>
</div>
<p> </p>
<p>app.json是对小程序的全局配置。主要包括pages:页面组,window:框架样式(状态栏、导航条、标题、窗口背景色),tabBar:底部菜单,networkTimeout:网络超时设置,debug:开启debug模式;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">app.json</span>
<span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">pages</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:[
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">pages/index/index</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">pages/logs/logs</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
],
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">window</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">backgroundTextStyle</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">light</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">navigationBarBackgroundColor</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">#000</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">navigationBarTitleText</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">WeChat</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">navigationBarTextStyle</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">white</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
}</span></pre>
</div>
<p> </p>
<p>app.wxss 默认为全局样式,作用所有页面。</p>
<p>创建页面:在pages目录下的文件夹是由四个同名不同类型文件组成。<code>.js</code>是脚本文件,<code>.json</code>是配置文件,<code>.wxss</code>是样式表文件,<code>.wxml</code>是页面结构文件,其中json和wxss文件为非必须(默认会继承app的json和wxss默认设置)。</p>
<p>在pages目录下的文件夹中的<code>.js</code>脚本文件使用Page()注册一个页面</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">Page({
data: {text: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">This is page data.</span><span style="color: rgba(128, 0, 0, 1)">"</span>},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">页面数据,用来维护视图,json格式</span>
onLoad: function(options) {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听加载</span>
onReady: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听初次渲染完成</span>
onShow: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听显示</span>
onHide: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听隐藏</span>
onUnload: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听卸载</span>
onPullDownRefresh: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听下拉</span>
onReachBottom: function() {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听上拉触底</span>
onShareAppMessage: function () {},<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听右上角分享
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如下为自定义的事件处理函数(视图中绑定的)</span>
viewTap: function() {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">setData设置data值,同时将更新视图</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.setData({text: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Set some data for updating view.</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">})
}
})</span></pre>
</div>
<p>视图与事件绑定</p>
<p>在每个页面中的wxml文件中,对页面相应的js中data进行数据绑定,以及自定义事件的绑定。</p>
<div class="cnblogs_code">
<pre><!--{{}}绑定data中的指定数据并渲染到视图-->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">title</span><span style="color: rgba(128, 0, 0, 1)">"</span>>{{text}}</view>
<!--wx:for获取数组数据进行循环渲染,item为数组的每项-->
<view wx:<span style="color: rgba(0, 0, 255, 1)">for</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{{array}}</span><span style="color: rgba(128, 0, 0, 1)">"</span>> {{item}} </view>
<!--wx:if条件渲染-->
<view wx:<span style="color: rgba(0, 0, 255, 1)">if</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{{view == 'WEBVIEW'}}</span><span style="color: rgba(128, 0, 0, 1)">"</span>> WEBVIEW </view>
<view wx:elif=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{{view == 'APP'}}</span><span style="color: rgba(128, 0, 0, 1)">"</span>> APP </view>
<view wx:<span style="color: rgba(0, 0, 255, 1)">else</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{{view == 'MINA'}}</span><span style="color: rgba(128, 0, 0, 1)">"</span>> MINA </view>
<!--模板-->
<template name=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">staffName</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<view>FirstName: {{firstName}}, LastName: {{lastName}}</view>
</template>
<template <span style="color: rgba(0, 0, 255, 1)">is</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">staffName</span><span style="color: rgba(128, 0, 0, 1)">"</span> data=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{{...template.staffA}}</span><span style="color: rgba(128, 0, 0, 1)">"</span>></template>
<template <span style="color: rgba(0, 0, 255, 1)">is</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">staffName</span><span style="color: rgba(128, 0, 0, 1)">"</span> data=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{{...template.staffB}}</span><span style="color: rgba(128, 0, 0, 1)">"</span>></template>
<!--bindtap指定tap事件处理函数为ViewTap-->
<view bindtap=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ViewTap</span><span style="color: rgba(128, 0, 0, 1)">"</span>> 点我点我 </view></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">Page({
data: {</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">data数据主要用于视图绑定</span>
text:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">我是一条测试</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
array:[</span><span style="color: rgba(128, 0, 128, 1)">0</span>,<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">],
view:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">APP</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
template:{
staffA: {firstName: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Hulk</span><span style="color: rgba(128, 0, 0, 1)">'</span>, lastName: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Hu</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">},
staffB: {firstName: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Shang</span><span style="color: rgba(128, 0, 0, 1)">'</span>, lastName: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">You</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">}
}
},
ViewTap:function(){console.log(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">额,点到我了了~</span><span style="color: rgba(128, 0, 0, 1)">'</span>)}<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自定义事件,主要用于事件绑定</span>
})</pre>
</div>
<p>样式</p>
<p>在每个页面中的wxss文件中,对wxml中的结构进行样式设置,等同于css,扩展了rpx单位。</p>
<h3><strong> rpx</strong></h3>
<p>小程序编译后,rpx会做一次px换算(小程序开发者工具在初始渲染一个页面时会首先获取设备宽度deviceWidth和dpr)</p>
<p>rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。</p>
<p>由此可以看出,小程序在实现rpx转换时,不论是什么屏幕的手机,都是将屏幕宽度固定设为750rpx,然后根据实际屏幕的设备像素比<code>dpr</code>(dpr = 设备像素 / css像素)来进行转换的。具体对应关系如下:</p>
<p>1rpx = (number/ 750) * 设备宽度 px</p>
<p>原文</p>
<p>https://www.cnblogs.com/fuyaozhishang/p/10231430.html</p>
<p>https://segmentfault.com/a/1190000018689948</p><br><br>
来源:https://www.cnblogs.com/xjy20170907/p/12192093.html
頁:
[1]