目录
小程序中如何进行接口请求?会不会跨域,为什么
1. 利用 wx.request API进行接口请求
wx.request({
url: 'https://showme.myhope365.com/api/cms/article/open/list',
method: "POST",
data: {
pageNum: 1,
pageSize: 10
},
header: {
"content-type": "application/x-www-form-urlencoded"
},
success: res => {
console.log(res.data.rows)
}
})
参数说明
- url 开发者服务器接口地址。注意这里需要配置域名
- data 请求的参数
- header 设置请求的 header,header 中不能设置 Referer,默认header['content-type'] = 'application/json'
- method(需大写)有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
- dataType json 回包的内容格式,如果设为json,会尝试对返回的数据做一次 JSON解析
- success 收到开发者服务成功返回的回调函数。
- fail 接口调用失败的回调函数
- complete 接口调用结束的回调函数(调用成功、失败都会执行)
2. 不会跨域
3. 跨域问题的出现是因为浏览器在进行请求时存在同源策略, 但是微信小程序不受同源策略的影响.所以不存在跨域问题
小程序的常用命令有哪些
引用数据
{ {}} 小程序中任何需要获取数据的地方都需要用{ {}},包括标签内的属性
逻辑渲染
wx:if wx:else wx:elif 条件渲染
1. 使用 wx:if="{ {condition}}" 来判断是否需要渲染该代码块
2. 使用 wx:elif 和 wx:else 来添加一个 else 块
3. 因为 wx:if 是一个控制属性,需要将它添加到一个标签上。
hidden 条件渲染
wx:if在不满足条件的时候会删除掉对应的DOM
hidden属性则是通过display属性设置为none来进行条件渲染
列表渲染
wx:for wx:for-item wx:for-index
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。
使用 wx:for-item 指定数组当前元素的变量名,使用 wx:for-index 指定数组当前下标的变量名。
<view wx:for="{
{array}}" wx:for-index="idx" wx:for-item="itemName">
{
{idx}}: {
{itemName.name}}
</view>
wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/> 中的输入内容, <switch/> 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key 的值以两种形式提供:
- 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 保留关键字 this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
引用
WXML 提供两种文件引用方式import和include。
import
需要注意的是 import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件中 import 的 template,简言之就是 import 不具有递归的特性。
include
include 可以将目标文件中除了 <template/> <wxs/> 外的整个代码引入,相当于是拷贝到 include 位置。
你认为微信小程序的优点是什么,缺点是什么
优势
- 微信助理,容易推广。在微信中,小程序拥有众多入口,例如附近的小程序、小程序码、分享、发现-小程序等五十多个的入口。这些入口有助于企业更好的获取流量,从而进行转化、变现。
- 使用便捷。用户在使用小程序时,只需要轻轻点一下就可以使用,更加符合用户对使用方便、快捷的需求,所以小程序的用户数量不断增加。
- 体验良好,有接近原生app的体验 。在微信生态里,小程序在功能和体验上是可以秒杀掉 H5 页面的,H5 页面经常出现卡顿、延时、加载慢、权限不足等原因,而这些问题在小程序里都不会出现。
- 成本更低,从开发成本到运营推广成本,小程序的花费仅为APP的十分之一,无论是对创业者还是传统商家来说都是一大优势。
不足
- 单个包大小限制为2M,这导致无法开发大型的应用,采用分包最大是20M(这个值一直在变化,以官网为准)。
- 需要像app一样审核上架,这点相对于H5的发布要麻烦一些。
- 处处受微信限制。例如不能直接分享到朋友圈,涉及到积分,或者虚拟交易的时候,小程序也是不允许的
微信小程序中的js和浏览器中和node中的区别
浏览器中JS
- ES
- DOM
- BOM
Node中的JS
- ES
- NPM
- Native
小程序中的JS
- ES
- 小程序框架
- 小程序API
微信小程序中的数据渲染浏览器中有什么不同
1. 浏览器中渲染是单线程的。
2. 小程序中的运行环境分成渲染层和逻辑层, WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
小程序中如何渲染数据
1. WXML模板使用 view 标签,其子节点用 { { }} 的语法绑定一个 msg 的变量。
2. 在 JS 脚本使用 this.setData 方法把 msg 字段设置成 “Hello World”。
简述一下微信小程序中通讯模型
小程序中通讯模型
小程序的渲染层和逻辑层分别由2个线程管理:
渲染层的界面使用了WebView 进行渲染;
逻辑层采用JsCore线程运行JS脚本。
一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端做中转,逻辑层发送网络请求也经由微信客户端转发。
js是单线程的, 但是渲染层和逻辑层是由两个线程管理的
谈谈对微信小程序中生命周期函数的理解
程序APP中
- onLaunch: 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
- onShow:当小程序启动,或从后台进入前台显示,会触发 onShow
- onHide:当小程序从前台进入后台,会触发 onHide
- onError:当小程序发生脚本错误,或者 API 调用失败时,会触发 onError 并带上错误信息
- 其他字段:可以添加任意的函数或数据到 Object 参数中,在App实例回调用 this 可以访问。
App({
onLaunch: function(options) {},
onShow: function(options) {},
onHide: function() {},
onError: function(msg) {},
globalData: 'I am global data'
})
在其他JS中可以通过getApp()获取App实例,之后可以获取到定义在App实例上的数据。
页面
- onLoad:生命周期函数--监听页面加载,触发时机早于onShow和onReady
- onReady:生命周期函数--监听页面初次渲染完成
- onShow:生命周期函数--监听页面显示,触发事件早于onReady
- onHide:生命周期函数--监听页面隐藏
- onUnload:生命周期函数--监听页面卸载
Page({
data: { text: "This is page data." },
onLoad: function(options) { },
onReady: function() { },
onShow: function() { },
onHide: function() { },
onUnload: function() { },
onPullDownRefresh: function() { },
onReachBottom: function() { },
onShareAppMessage: function () { },
onPageScroll: function() { }
})
组件
生命周期 |
参数 |
描述 |
created |
无 |
在组件实例刚刚被创建时执行 |
attached |
无 |
在组件实例进入页面节点树时执行 |
ready |
无 |
在组件在视图层布局完成后执行 |
moved |
无 |
在组件实例被移动到节点树另一个位置时执行 |
detached |
无 |
在组件实例被从页面节点树移除时执行 |
error |
|
每当组件方法抛出错误时执行 |
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
})
组件所在页面的生命周期
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
生命周期 |
参数 |
描述 |
show |
无 |
组件所在的页面被展示时执行 |
hide |
无 |
组件所在的页面被隐藏时执行 |
resize |
|
组件所在的页面尺寸变化时执行 |
Component({
pageLifetimes:{
show:function(){
// 页面被展示
},
hide:function(){
// 页面被隐藏
},
resize:function(size){
// 页面尺寸变化
}
}
})
微信小程序中如何进行事件的定义,传参
事件定义 bind开头
在小程序中绑定事件可以以bind开头然后跟上事件的类型,如bindtap绑定一个点击事件,对应的值是一个字符串,需要在page构造器中定义同名函数,每次触发事件之后就会执行对应函数的内容。
阻止事件冒泡 catch开头
在小程序中除了通过bind之外,还可以通过catch进行事件绑定,通过catch绑定的事件不会触发事件冒泡。
事件捕获 capture-bind开头
事件的触发分为两个阶段,首先是捕获阶段,其次是冒泡阶段。默认情况下事件都是在冒泡阶段触发。如果希望事件可以在捕获阶段触发,可以通过capture-bind进行事件绑定。
事件传参 data-
在小程序中进行事件传参不能像传统的Web项目中一样,在括号里写参数。在小程序中需要在标签上通过data-方式定义事件所需的参数。
<!-- data-参数名=’参数值’ -->
<view bindtap="handleTap" data-msg="我是事件的参数">点击事件</view>
每个事件回调触发时,都会收到一个事件对象,通过这个对象可以获取路由传递的参数。
handleTap(e){
console.log("执行了点击事件");
// 通过currentTarget中的dataset属性可以获取时间参数
console.log(e.currentTarget.dataset.msg);
}
关于事件对象其他属性
- type 事件类型
- timeStamp 页面打开到触发事件所经过的毫秒数
- target 触发事件的组件的一些属性值集合
- currentTarget 当前组件的一些属性值集合
- detail 额外的信息
- touches 触摸事件,当前停留在屏幕中的触摸点信息的数组
- changedTouches 触摸事件,当前变化的触摸点信息的数组
这里需要注意的是target和currentTarget的区别,currentTarget为当前事件所绑定的组件,而target则是触发该事件的源头组件。
wxss和css有什么区别
尺寸单位 rpx
在WXSS中,引入了rpx尺寸单位。引用新尺寸单位的目的是,适配不同宽度的屏幕,开发起来更简单。
在小程序中,规定所有手机的屏幕宽度都是750rpx,所以在不同尺寸的屏幕下1rpx的宽度都不同。
1rpx = (屏幕宽度/750)px
在iphone6手机下,屏幕宽度是375px,所以1rpx=0.5px。
样式的导入
在小程序中,样式引用是这样写:@import './test_0.wxss'
由于WXSS最终会被编译打包到目标文件中,用户只需要下载一次,在使用过程中不会因为样式的引用而产生多余的文件请求。
小程序中的样式选择器
目前支持的选择器。
小程序如何进行页面的跳转传参以及接收数据
标签式跳转
<navigator url=”页面地址” target=“self // 当前页面小程序的 || miniProgram // 其他页面小程序”><navigator>
wx.navigateTo
wx.navigateTo({
url: 'test?id=1',
})
保留当前页面,只能打开非 tabBar 页面。
wx.redirectTo
wx.redirectTo({
url: 'test?id=1'
})
关闭卸载当前页面,只能打开非 tabBar 页面。
wx.switchTab
--------不能进行页面传参
wx.switchTab({
url: '/index'
})
关闭所有非tabbar页面, 只能打开 tabBar 页面。
wx.reLaunch
wx.reLaunch({
url: 'test?id=1'
})
关闭卸载所有页面,可以打开任意页面。
wx.navigateBack
wx.navigateBack({
delta: 2 //返回的页面数,如果 delta 大于现有页面数,则返回到首页。
})
返回前面的页面,可以指定返回多少页,如果用过redirectTo,那么被关闭的页面将返回不去
路由跳转传参
路由跳转传参可以通过?的方式拼接参数。跳转到指定界面之后,可以在该页面的onLoad方法中的options参数(本身是个对象)拿到路由跳转的参数。
小程序如何进行本地存储
小程序提供了读写本地数据缓存的接口,通过wx.setStorage写数据到缓存,在小程序中几乎所有接口都是异步的,这里存储数据也是一个异步操作,如果希望进行同步存储需要调用wx.setStorageSync。
异步存储
wx.setStorage({
data: {name:"天亮教育",age:4},
//需要存储的内容。只支持原生类型、Date、及能够通过JSON.stringify序列化的对象。
key: 'list',//本地缓存中指定的 key
})
同步存储
wx.setStorageSync('list1', {name:"尚云科技",age:5})
异步读取
wx.getStorage({
key: 'list',
success(res){
console.log(res);
}
})
同步读取
const list = wx.getStorageSync('list')
缓存的限制和隔离
- 小程序宿主环境会管理不同小程序的数据缓存,不同小程序的本地缓存空间是分开的,每个小程序的缓存空间上限为10MB,如果当前缓存已经达到10MB,再通过wx.setStorage写入缓存会触发fail回调。
- 小程序的本地缓存不仅仅通过小程序这个维度来隔离空间,考虑到同一个设备可以登录不同微信用户,宿主环境还对不同用户的缓存进行了隔离,避免用户间的数据隐私泄露。
- 由于本地缓存是存放在当前设备,用户换设备之后无法从另一个设备读取到当前设备数据,因此用户的关键信息不建议只存在本地缓存,应该把数据放到服务器端进行持久化存储。
谈谈你对微信小程序请求封装的理解
由于我们后台请求接口的数据格式都是表单格式的,每次发送请求会很麻烦,都需要指定请求头,另外我们这里回调函数的方式解决异步问题,写起来也可能会出现回调地域的问题。在这里我们如果想解决这些问题,就涉及到了http请求的封装。
封装的优点
提高代码的复用性
提高代码安全性
便于修改增加可维护性
简化外部调用,便于开发
符合高内聚低耦合特性
作用
- 添加统一的请求配置
- 可以添加请求拦截器和响应拦截器,在请求和响应之前加一些通用的处理。
封装的实现
function request(options) {
// 请求拦截器
// ...
// 1. 加一些统一的参数,或者配置
if (!options.url.startsWith("https://") && !options.url.startsWith("http://")) {
options.url = "https://showme.myhope365.com" + options.url
}
// 默认的请求头
let header = {
"content-type": "application/x-www-form-urlencoded",
};
if (options.header) {
header = {
...header,
...options.header
}
}
return new Promise((reslove, reject) => {
// 调用接口
wx.request({
// 默认的配置
// 加载传入的配置
...options,
header,
success(res) {
// 响应拦截器,所有接口获取数据之前,都会先执行这里
// 1. 统一的错误处理
if (res.statusCode != 200) {
wx.showToast({
title: '服务器异常,请联系管理员',
})
}
reslove(res)
},
fail(err) {
reject(err)
}
})
})
}
export function get(url, options = {}) {
return request({
url,
...options
})
}
export function post(url, data, options = {}) {
return request({
url,
data,
method: "POST",
...options
})
}
小程序如何实现数据驱动视图
在JS文件中的data中动态操控数据:使用 this.setData方法修改data中的数据;
在wxml文件通过{ {}}将数据绑定,即可在页面中显示
<!-- page.wxml -->
<view>{
{text}}</view>
// page.js
Page({
data: {
text: '天亮教育',
},
onLoad(){
console.log(this.data.text)
}
})
如果涉及到更新,这里可以调用Page实例提供的setData把数据传递给渲染层,从而达到更新界面的目的。由于小程序的渲染层和逻辑层分别在两个线程中运行,所以setData传递数据实际是一个异步的过程,所以setData的第二个参数是一个callback回调,在这次setData对界面渲染完毕后触发。
setData其一般调用格式是 setData(data, callback),其中data是由多个key: value构成的Object对象。
// page.js
Page({
onLoad: function(){
this.setData({
text: 'change data'
}, function(){
// 在这次setData对界面渲染完毕后触发
})
}
})
注意事项
- 直接修改 Page实例的this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
- 由于setData是需要两个线程的一些通信消耗,为了提高性能,每次设置的数据不应超过1024kB。
- 不要把data中的任意一项的value设为undefined,否则可能会有引起一些不可预料的bug。
为什么微信小程序会出现登录鉴权的问题, 如何解决
原因
通常后端采用的登录鉴权方式是通过cookie的方式进行的鉴权,即登录成功之后,后端会给我们cookie上增加一个JSESSIONID,这个JESSIONID就标识了当前登录用户的身份。
在浏览器中,我们每次发送请求都会携带cookie,所以说在浏览器中我们登录成功之后就可以直接调用登录之后才能访问的接口。但是在小程序端,小程序默认不会帮我们在发送请求的时候带上cookie,这个时候就需要我们手动添加请求cookie了。
解决方法
1. 在登录成功之后,我们获取到后台返回的cookie中的JESSIONID并进行记录。
2. 在每次发送请求的时候,在请求头中添加上cookie属性。
function request(options) {
// 请求拦截器
// ...
// 1. 加一些统一的参数,或者配置
if (!options.url.startsWith("https://") && !options.url.startsWith("http://")) {
options.url = "https://showme.myhope365.com" + options.url
}
// 默认的请求头
let header = {
"content-type": "application/x-www-form-urlencoded",
// 加上统一的cookie
"cookie": wx.getStorageSync("cookie") || ""
};
if (options.header) {
header = {
...header,
...options.header
}
}
return new Promise((reslove, reject) => {
// 调用接口
wx.request({
// 默认的配置
// 加载传入的配置
...options,
header,
success(res) {
// 响应拦截器,所有接口获取数据之前,都会先执行这里
// 1. 统一的错误处理
if (res.statusCode != 200) {
wx.showToast({
title: '服务器异常,请联系管理员',
})
}
reslove(res)
},
fail(err) {
reject(err)
}
})
})
}
对小程序中常见的开放能力API有什么了解
获取网络状态 wx.getNetworkType()
从网络上下载文档 wx.downloadFile()
下载成功之后进行预览文档 wx.openDocument()
扫码能力 wx.scanCode()
获取当前微信用户信息 wx.getUserProfile()
小程序的父子传参和vue中的有什么区别
小程序父子组件通信
1、父组件给子组件传值
在子组件中定义属性
properties: {
// 复杂定义
name:{
type: String,
value:'张三丰'
},
// 简单定义
name2:String
},
父组件在引用子组件的时候通过设置属性的方式给子组件传值
2、 子组件给父组件传值
在组件中绑定一个自定义事件
// 引用了自定义的组件, 绑定了myevent事件,这个事件对应的是parentEvent方法
<test-button name="张无忌" bindmyevent="parentEvent"></test-button>
在子组件中触发这个事件,可以给父组件传值。
子组件中通过triggerEvent触发事件
methods: {
方法名字: function(){
var myEventDetail = {}
// detail对象,提供给事件监听函数
var myEventOption = {}
// 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
}
}
区别
父传子 properties接收
子传父 triggerEvent方法
谈谈你对behavior的理解
behaviors
是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins” 或 “traits”。
每个 behavior
可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior
,behavior
也可以引用其它 behavior
组件中使用
组件引用时,在 behaviors
定义段中将它们逐个列出即可。
// my-component.js
var myBehavior = require('my-behavior')
Component({
behaviors: [myBehavior],
properties: {
myProperty:{ type: String }
},
data:{ myData:'my-component-data'},
created:function(){
console.log('[my-component] created')
},
attached:function(){
console.log('[my-component] attached')
},
ready:function(){
console.log('[my-component] ready')
},
methods:{
myMethod:function(){
console.log('[my-component] log by myMethod')
},
}
})
同名字段的覆盖和组合规则
组件和它引用的 behavior
中可以包含同名的字段,对这些字段的处理方法如下:
- 如果有同名的属性或方法:
- 若组件本身有这个属性或方法,则组件的属性或方法会覆盖
behavior
中的同名属性或方法; - 若组件本身无这个属性或方法,则在组件的
behaviors
字段中定义靠后的behavior
的属性或方法会覆盖靠前的同名属性或方法; - 在 2 的基础上,若存在嵌套引用
behavior
的情况,则规则为:引用者
behavior
覆盖被引用的
behavior
中的同名属性或方法。
- 若组件本身有这个属性或方法,则组件的属性或方法会覆盖
- 如果有同名的数据字段:
- 若同名的数据字段都是对象类型,会进行对象合并;
- 其余情况会进行数据覆盖,覆盖规则为:
引用者
behavior
>被引用的
behavior
、靠后的
behavior
>靠前的
behavior
。(优先级高的覆盖优先级低的,最大的为优先级最高)
- 生命周期函数和 observers 不会相互覆盖,而是在对应触发时机被逐个调用:
- 对于不同的生命周期函数之间,遵循组件生命周期函数的执行顺序;
- 对于同种生命周期函数和同字段 observers ,遵循如下规则:
behavior
优先于组件执行;被引用的
behavior
优先于引用者
behavior
执行;靠前的
behavior
优先于靠后的
behavior
执行;
- 如果同一个
behavior
被一个组件多次引用,它定义的生命周期函数和 observers 不会重复执行。
如何优化首次加载小程序的速度
控制代码包的大小
(1)代码包的体积压缩可以通过勾选开发者工具中“上传代码时,压缩代码”选项
(2)及时清理无用的代码和资源文件
(3)减少资源包中的图片等资源的数量和大小
分包加载---预加载
将用户访问率高的页面放在主包里,将访问率低的页面放入子包里,按需加载;
采用子包预加载技术,并不需要等到用户点击到子包页面后在下载子包
预请求
请求可以在页面onLoad就加载,不需要等页面ready后在异步请求数据;
尽量减少不必要的https请求,可使用 getStorageSync() 及 setStorageSync() 方法将数据存储在本地
避免不当的使用setData
不要过于频繁调用setData,应考虑将多次setData合并成一次setData调用
使用自定义组件
对于一些独立的模块我们尽可能抽离出来,这是因为自定义组件的更新并不会影响页面上其他元素的更新;各个组件也将具有各自独立的逻辑空间。每个组件都分别拥有自己的独立的数据、setData调用
如何实现瀑布流效果
实现瀑布流
1. 准备左右两个数组。
2. 逐步处理列表的数据,把数据放到高度比较小数组中。这个时候我们需要获取到图片的高度,并且计算左右两边数组高度,把新的数据放到高度比较小的数组中。
实现的步骤
1. 请求后端的数据
2. 设置需要的属性-------leftList、rightList、leftHeight、rightHeight
3. 遍历数组,通过wx.getImageInfo获取到每个元素图片的宽度高度(需要配置download的域名)
4. 判断这个元素应该被放在左边还是右边(放在数组高度低的一边)
5. 处理完数据之后,把数据设置到data上
6. 在前端展示这些数据(图片需要加上mode="widthFix",宽度固定,高度自适应,保持宽高比)
关于瀑布流实现了解更多请点击这里
谈谈你对WebSocket的理解
WebSocket协议有哪些特点
1. webSocket是一种在单个TCP连接上进行全双工通信的协议
2.websocket建立连接时,数据是通过http传输的,建立连接后就不需要http协议了。
3.websocket建立连接后就是全双工模式,也是基于tcp协议。
4.建立连接之后,不必在客户端发送request之后服务器才能返回信息到浏览器,这时候服务器有主动权,允许可以随时发消息给客户端
5.发送的信息中不必带有head部分信息了,相对于http来说,降低了服务器的压力,极大的减少了不必要的网络流量与延迟。
6.没有同源限制,客户端可以与任意服务器通信
7.协议标识符是ws(如果加密,则为wss),服务器网址就是 URL
关于websocket了解更多请点击这里