Mytu's BlogMytu's Blog
Home
XH蒜花
语雀
Github
Home
XH蒜花
语雀
Github
  • 欢迎光临

    • 关于我
  • 基础总结

    • HTML
    • CSS
    • JavaScript
      • ES6
    • TypeScript
    • JQuery
    • Vue2
      • Vue
      • Vuex
      • 基础
      • 进阶
      • 实战
    • Vue3
      • 基础
      • 实战
    • React
    • Uni-app
    • 小程序
      • 实战
    • NodeJs
    • Git
    • MySql
    • Webpack
    • Other
  • 前端面试

    • 八股文
  • Free Style

    • 中午吃什么?

01

JSON 配置

配置文件,app.json是当前小程序的全局配置,page.json是局部配置,可以独立定义每个页面的一些属性

https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html

pages字段

存放小程序所有页面路径,模拟器会显示数组第一项的页面

tabBar字段

https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar

tab 栏可以通过tabBar配置,list表示tab 的列表,接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:

"tabBar": {
    "list": [
        {
        	//页面路径,必须在 pages 中先定义
            "pagePath": "pages/home/home",
            //tab 上按钮文字
            "text": "home",
            //图片路径,当 position 为 top 时,不显示 icon
            "iconPath": "./icon/首页_home.png",
            //选中时的图片路径
            "selectedIconPath": "./icon/首页_home (1).png"
        },
        {
            "pagePath": "pages/shopping/shopping",
            "text": "shopping",
            "iconPath": "./icon/购物车_shopping.png",
            "selectedIconPath": "./icon/购物车_shopping (1).png"
        }
    ],
    "color": "#666",
    "selectedColor": "#2F88FF",
    "backgroundColor": "#eee",
    "borderStyle": "white"
},

window字段

https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#window

用于设置小程序的状态栏、导航条、标题、窗口背景色

"window": {
	//下拉 loading 的样式,仅支持 dark / light
    "backgroundTextStyle": "dark",
     //是否开启全局的下拉刷新。
    "enablePullDownRefresh": true,
    //窗口的背景色
    "backgroundColor": "#fcf",
    //导航栏背景颜色
    "navigationBarBackgroundColor": "#ccf",
    //导航栏标题文字内容
    "navigationBarTitleText": "day01",
    //导航栏标题颜色,仅支持 black / white
    "navigationBarTextStyle": "black"
},

WXML 模板

标签

view是块级元素类似于div标签,text是行内元素类似于span标签,block是空标签类似于template标签

图片 image组件

小程序的image组件默认宽度320px,高度240px,使用mode属性来设置图片裁剪、缩放的模式

widthFix表示宽度占满,高度跟随原图比例做自适应,heightFix同理,其他模式无法显示全图

WXSS 样式

单位

尺寸单位为rpx可以根据屏幕宽度进行自适应。1px=2rpx

样式

对同一个选择器,页面样式表比公共样式表拥有更高的权重,页面的根元素是page

JS 逻辑交互

处理一些逻辑事件,接受一个对象类型参数

全局:App()

局部单个页面:Page()

数据data

data是一个对象,使用时用双花括号将变量包起来,文本渲染用双花括号,属性值也是用双花括号

data-xxx为自定义属性

<checkbox data-num="{{num}}" checked="{{checked}}" />
Page({
  data: {
    checked: false,
      num: 1,
  },
});

上面的checked值还可以写成如下:

<checkbox checked="{{false}}" />

注意:如果直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值

数据路径运算:显示对象的某一属性值或数组的某一下标值称为数据路径运算

<view>{{obj.name}}</view>
<view>{{arr[0]}}</view>

全局数据

全局数据定义在app.js的globalData中,**getApp()**获取到到App实例之后在通过app.globalData.xxx获取到数据

const app = getApp()
const safeAreaHeight = app.globalData.safeAreaHeight

02

事件

事件绑定

用bind来绑定事件,用catch来捕获事件,不能在方法名后面携带参数

语法:bind(catch)+事件类型,bind(catch)事件类型之间可以加冒号

注意点:小程序的事件名直接写在最外层,不需要写在methods里面

事件对象

用基础事件对象e来接收,在基础事件对象中可以获取到id属性和data-xx自定义属性

currentTarget和target的区别

事件是绑定在谁身上,currentTarget就指向谁

事件触发在谁身上,target就指向谁

setData修改数据

直接修改this.data只是改了逻辑层的数据,没有更新视图层

调用this.setData既修改了逻辑层的数据,还更新了视图层

1,setData第一个参数是对象类型,第二个参数更新渲染完毕后的回调函数

2,尽可能的去合并setData,setDatab比较消耗性能

3,可以不经过data定义,直接setData新增字段

4,数组或对象的某一项可以单独修改

数据双向绑定

1,输入框的val值通过bindinput的事件对象e拿到数据,在通过this.setData来更新data里面的值

2,model:value支持数据双向绑定,但是不支持数据路径的数据双向绑定

if和hidden

wx:if为真时才渲染,如果不经常切换使用wv:if,多个条件判断时候搭配wx:elif,wx:else来使用

hidden为真时只是样式上被隐藏了,如果频繁切换使用hidden

判断多个组件标签时候可以用block标签包裹,block不会在页面中做任何渲染,只接受控制属性

for

wx:for,默认的数组项变量名为item,默认下标变量名为index

使用wx:for-item来改变数组项的变量名,使用wx:for-index来改变下标的变量名

wx:key表示唯一的标识符

1,**this,item本身是一个唯一的字符串或者数字才可以,能用index作为key值但是不推荐

2,id

03

路由跳转

switchTab

跳转到tabBar页面用switchTab,此时页面全部出栈,只留下新的 Tab 页面

<!-- 跳转到tab页面 -->
<button bindtap="toTabB">跳转到tabB页面</button>
<!-- 导航组件方式 -->
<navigator url="../tabB/tabB" open-type="switchTab">跳转到tabB页面</navigator>
toTabB() {
    wx.switchTab({
        url: '../tabB/tabB',
    })
}

navigateTo

跳转到普通页面用navigateTo,可以传参,在通过onLoad的参数获取

传参方式是在路径后写问号,问号后是key=val这种形式,不同的key=va1之间用&去隔开

还有两种方式可以在路径后传参,是redirectTo和reLaunch,switchTab不能传参

<!-- 跳转到普通页面 -->
<button bindtap="toPageX">跳转到普通页面</button>
<!-- 导航组件方式 -->
<navigator url="../x/x?a=1" open-type="navigate">跳转到普通页面</navigator>
toPageX() {
    wx.navigateTo({
        url: '../x/x?a=1&b=2&id=3',
    })
}

navigateBack

返回用navigateBack,注意导航组件的方式不需要写url了,此时页面不断出栈

默认返回上一页,delta是返回的层级,如果返回层级大于现有的页面只能返回最开始的页面

<button bindtap="goBack">返回上一页</button>
<navigator open-type="navigateBack" delta="1">返回上一页</navigator>
goBack() {
    wx.navigateBack({
        delta: 1,
    })
},

reLaunch

重启动用reLaunch,此时页面全部出栈,只留下新的页面,点击小房子图标会回到路由第一个路径的页面

<button bindtap="reLaunchToZ">重启动到页面z</button>
<navigator url="../z/z" open-type="reLaunch">重启动到页面z</navigator>
reLaunchToZ() {
    wx.reLaunch({
        url: '../z/z',
    })
},

redirectTo

重定向用redirectTo,此时当前页面出栈,新页面入栈

<button bindtap="redirectToZ">重定向到页面z</button>
<navigator url="../z/z" open-type="redirect">重定向到页面z</navigator>
redirectToZ() {
    wx.redirectTo({
        url: '../z/z',
    })
},

页面生命周期

onLoad(query):页面加载时触发

onShow():页面展示或切入前台时触发

onReady():页面初次渲染完成时触发

onHide():页面隐藏或切入后台时触发

onUnload():页面卸载时触发

1,页面进栈执行onLoad onShow onReady

2,隐藏执行onHide,出栈执行onUnload,多次显示执行onShow

3,特殊:tab页面从头到尾只会执行一次onLoad,切换tab执行的是onHide和onShow,

  按照文档,tab切换是属于出栈的,但是不会执行onUnload和onLoad

4,onLoad中能获取和更新data的数据一般还会在onLoad里面去调用接口获取数据渲染页面,还可以在 onLoad  的参数中获取到当前页面路径中的参数

5,什么情况会执行onUnload? 例如:1.y返回x,y出栈 2.y重定向到z,y出栈 3.y重启动到z,除了z之外的页面都出栈

全局生命周期

onLaunch():监听小程序初始化,只会执行一次,比如去调用接口,判断手机是否需要进行安全区域适配

onShow():监听小程序启动或者是切前台

onHide():监听小程序切后台

WXS语法

在视图层里不能运行js,wxs可以在模板中去使用js处理一些数据,不支持es6语法,有点类似vue的过滤器

导出时使用module.exports导出方法或变量,引入wxs路径(src)时给wxs模块(module)起名字来使用

<wxs src="../wxs/price.wxs" module="priceModule" />
<view>
    <!-- {{price.toFixed(2)}} -->
    {{price2}}//通过this.setData修改

    {{priceModule.handlePrice(price)}}
    {{priceModule.handlePrice2(price)}}
</view>
function handlePrice(price) {
    return price.toFixed(2)
}

function handlePrice2(price) {
    return price.toFixed(2) + '元'
}

module.exports = {
    handlePrice: handlePrice,
    handlePrice2: handlePrice2
}

数据缓存

小程序中不需要通过JSON.stringify序列化的对象

同步

存缓存:wx.setStorageSync(key, value)

取缓存:wx.getStorageSync(key)

删某一个缓存:wx.removeStorageSync(key)

清空缓存:wx.clearStorageSync()

异步

存进去的缓存不需要马上用到,就可以用异步,不会阻塞下面的执行

异步会返回Promise对象,因此缓存异步语法支持.then操作

存缓存:wx.setStorage({

key: xxx,

data: xxx,

	  		success() {},     //成功的回调函数,代表存储成功

fail() {} // 失败的回调

})

取缓存:wx.getStorage({

key: xxx,

success(res) {

console.log(res.data)    //拿到当前这个key的值

}

	 })

删某一个缓存:wx.removeStorage({
key: 'str',
success() { }
})

清空缓存:wx.clearStorage({
success() {}
})

或者:wx.clearStorage().then(() => { })

day04

自定义组件的使用

1,创建:新建Component,引入时在usingComponents里引入,左边写自定义组件名右边写文件路径,使用  时把自定义组件名当标签名使用

2,properties为组件的属性列表,父传子过来的参数 (类似于Vue的props),定义属性简化的写法为:属性:类型

  完整写法为:属性: {type: xxx,value: xxx'}

3,组件的方法要写在methods里面,可以在这里触发自定义事件,由父级去监听

4,组件自定义事件语法为:this.triggerEvent(事件名,参数(子传父的数据),事件选项(了解即可) ),要写多个  参数时采用对象的方式,类似Vue的this.$emit(事件名,参数1,参数2,...)

5,使用时与vue不同之处,:parentdata="msg" 变成 parentdata="",冒号变成双花括号

  @clickChild="clickChild" 变成 bind:clickChild="clickChild",**@变成bind**

注意:在自定义组件样式中不要使用id选择器

插槽

匿名插槽:组件内 微信小程序不支持默认值,调用时在组件标签内传递插槽内容

具名槽口: 组件内调用时通过slot属性指定对应的名称

小程序默认不支持多个插槽,需要去子组件的js配置,开启多个插槽选项options: { multipleSlots: true }

下拉刷新

1,"enablePullDownRefresh": true:开启下拉刷新(json文件中配置)

2,onPullDownRefresh:监听下拉刷新事件,可以在这里去发送请求,获取 最新的数据,重新渲染页面

3,onPullDownRefresh:停止下拉刷新

4,startPullDownRefresh:开始下拉刷新的动作,会自动触发onPullDownRefresh里面的逻辑

上拉触底

1,onReachBottom:监听上拉触底

2,onReachBottomDistance:页面上拉触底事件触发时距页面底部距离(json文件中配置)

项目

底部安全区域适配

通过获取系统信息,判断手机是否有底部安全区域

1,wx.getSystemInfo:获取系统信息,可以通过成功回调函数的参数可以拿到对应的属性值screenHeight(屏幕        高度)和safeArea(安全区域)

2,screenHeight - safeArea.bottom即可得到底部安全区域高度

3,在把底部安全区域高度存缓存里面,要用的时候在取出来

App({
    onLaunch() {
        wx.getSystemInfo({
            success: (res) => {
                // console.log(res);
                const {
                    screenHeight,
                    safeArea
                } = res
                let safeAreaHeight = screenHeight - safeArea.bottom
                wx.setStorageSync('safeAreaHeight', safeAreaHeight)
            },
        })
    }
})
Page({
    data: {
        safeAreaHeight: 0
    },    
    onLoad() {
        const safeAreaHeight = wx.getStorageSync('safeAreaHeight')
        this.setData({
            safeAreaHeight
        })
    },
})
<view style="padding-bottom: {{safeAreaHeight}}px;">xxx</view>

方法二,直接存在全局数据里面,在通过App实例获取数据

App({
    globalData: {
        safeAreaHeight: 0
    },
    onLaunch() {
        wx.getSystemInfo({
            success: (res) => {
                // console.log(res);
                let {
                    screenHeight,
                    safeArea
                } = res
                this.globalData.safeAreaHeight = screenHeight - safeArea.bottom
                console.log(this.globalData.safeAreaHeight);
            },
        })
    }
})
let app = getApp()
Page({
    data: {
        safeAreaHeight: app.globalData.safeAreaHeight
    }
})

自定义tabBar

https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html

1,配置tabBar,配置custom字段,设置 "custom": true,开启自定义tabBar功能

2,新建custom-tab-bar的文件夹,并在其中添加名为index的组件页面

3,使用vant的Tabbar组件,wx:for渲染数据

4,通过onChange事件对象e拿到索引,根据索引来实现路由跳转(wx.switchTab)

5,去每个页面onShow生命周期中通过this.getTabBar获取组件实例,并调用 setData修改active的值来实现              tabBar图标的高亮

注意:使用自定义tabBar,tab页面会受安全区域影响,安全区域高度需要加上自定义tabBar的高度

自定义导航栏

1,去widow配置"navigationStyle": "custom"

2,创建自定义导航栏组件,使用固定定位到顶部,注意在wxss里面,不能使用本地图片

自定义按钮组件

1,封装按钮组件,在properties里面定义组件的属性数据通过父级传过来

2,在methods里面触发自定义事件,让父级监听

自定义底部文字组件

1,封装底部文字组件,在properties里面定义数组通过父级传过来,数据项使用wx:for循环

2,在properties里面定义底部安全区域通过父级传过来

获取用户信息wx.getUserProfile

1,调用wx.getUserProfile开放接口,获取用户信息,页面产生点击事件后才可调用

2,需要去调试基础库减低版本低于2.27.1(详情,本地设置,调试基础库)

<button bindtap="handleGetUserProfile">获取用户信息</button>
handleGetUserProfile() {
    wx.getUserProfile({
    	//必须写desc
        desc: "用于完善会员资料", //声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
        success: (res) => {
            console.log(res);
        },
        fail: (err) => {
            console.log(err);
        },
    });
},

如果基础库版本太高可以通过头像昵称填写能力获取

头像昵称填写能力

获取用户头像

1,需要将 button 组件 open-type 的值设置为 chooseAvatar,当用户选择需要使用的头像之后,可以通过 bindchooseavatar 事件回调获取到头像信息的临时路径

2,在通过事件对象e中获取到头像信息在显示在图片中

<button open-type="chooseAvatar" bind:chooseavatar="handChooseAvatar">获取用户头像</button>
<image src="{{avatarUrl}}" style="width: 100rpx;height: 100rpx;" />
handChooseAvatar(e) {
    console.log(e);
    this.setData({
        avatarUrl: e.detail.avatarUrl
    })
}

获取用户昵称

1,需要将 input 组件 type 的值设置为 nickname,当用户在此 input 进行输入时,键盘上方会展示微信昵称

2,在通过bindinput监听输入事件显示在页面中

注意:输入框是原生组件,pc端模拟器会有问题,开发者在使用到原生组件时尽量在真机上进行调试

<input type="nickname" placeholder="获取用户昵称" value="{{nickname}}" bindinput="handleInput" />
<view>昵称:{{nickname}}</view>
// 获取用户昵称,监听用户名称输入,pc端模拟器会有问题
handleInput(e) {
    console.log(e);
    this.setData({
        nickname: e.detail.value
    })
}

获取手机号

需要将 button 组件 open-type 的值设置为 getPhoneNumber

当用户点击并同意之后,可以通过 bindgetphonenumber 事件回调获取到动态令牌code,然后把code传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,用code来换取用户手机号。每个code有效期为5分钟,且只能消费一次

注意:个人开发者不能调用该接口,开发时可以用测试号体验

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNum">获取手机号</button>
//把e.detail.code通过接口给后端,后端拿到code后去微信后台换取手机号,然后再通过接口把手机号传给前端
getPhoneNum(e) {
    console.log(e);
},

获取位置wx.getLocation

1,在 app.json 中配置requiredPrivateInfos

2,还需要用户授权,小程序接口权限设置permission,scope.userLocation精确地理位置,desc为必填字段

3,调用 wx.openSetting 打开设置授权地理位置界面  ,这个api只能由用户主动产生点击行为去触发

<button bindtap="handleOpenSetting">点击授权地理位置</button>
onShow() {
    // 获取地理位置
    wx.getLocation({
        type: 'wgs84', //gps坐标
        // 如果授权过一次,后续用wx.getLocation获取地理位置默认都是成功
        success(res) {
            console.log(res);
            const latitude = res.latitude
            const longitude = res.longitude
            const speed = res.speed
            const accuracy = res.accuracy
        },
        // 如果拒绝过一次,后续用wx.getLocation获取地理位置默认都是失败
        fail: err => {
            console.log(err);
        }
    })
},
handleOpenSetting() {
    wx.openSetting()
},
"requiredPrivateInfos": [
    "getLocation"
],
"permission": {
    "scope.userLocation": {
        "desc": "收集地理位置为了更好的服务"  //接口用途说明
    }
}

打开地图选择位置wx.chooseLocation

在 app.json 中配置requiredPrivateInfos 在调用wx.chooseLocation即可

"requiredPrivateInfos": [
    "chooseLocation"
],
handleChooseLocation() {
    wx.chooseLocation({
        success: (res) => {
            console.log(res);
        },
        fail: (err) => {
            console.log(err);
        }
    })
}

打包

上传之后,去微信公众平台中的版本管理里面提交审核即可

分包

整个小程序,主包加分包不能超过20M,单个包不能超过2M

如果包太大可以使用分包,在 app.json subpackages 字段声明项目分包结构

{
  "pages":[
    xxx
  ],
  "subpackages": [
    {
      "root": "packageA",
      "pages": [
        "pages/cat",
        "pages/dog"
      ]
    }, {
      "root": "packageB",
      "name": "pack2",
      "pages": [
        "pages/apple",
        "pages/banana"
      ]
    }
  ]
}

wx.downloadFile

使用 wx.downloadFile 方法下载一个文件,下载成功之后会将文件保存到临时文件夹中,然后使用wx.openDocument 方法打开该文件,如果没有配置合法域名会报错,解决方法如下:

1,在详情=>本地设置=>不校验合法域名

2,在微信公众平台=>开发管理=>开发设置=>服务器域名中配置合法域名

onCheck() {
    wx.downloadFile({
        url: "https://hxyyxy.nwsuaf.edu.cn/docs/2020-08/db2f3058866c4280ac9b2e05410ea87c.pdf",
        success: function (res) {
            const filePath = res.tempFilePath;  //临时文件夹路径
            wx.openDocument({
                filePath: filePath,
            });
        },
    });
}
Prev
Uni-app
Next
NodeJs