解锁商机,原生小程序插件助力企业腾飞
883
2022-10-01
放心,手把手教你写微信小程序(自己写微信小程序)
微信小程序开发栏目今天详细教大家写微信小程序。
小程序的历史介绍
什么是微信小程序?
微信小程序,简称小程序。英文名mini program,是一种不需要-安装就可以直接使用的应用。他实现了触手可及的梦想。用户扫一扫或搜一下就可以直接打开应用。
为什么是微信小程序
微信有海量用户推广app或公众号成本太高开发适配成本低容易小规模试错,然后快速迭代跨平台
历史
2016年1月11日,张小龙,微信内部研究新的形态,应用号,后改名小程序。2016年8月12日,开始内测2017年1月9日,上线
#环境规范
小程序开发者工具
开发者工具介绍
快捷键:
1. ctrl + shift + F (搜索)2. alt + shift + F (代码格式化---VSCode)复制代码-
小程序原生框架
小程序的原生框架,mina框架 框架详情
小程序配置文件(写配置文件在微信开发者工具工具写,有提示)
小程序的模板语法
WXML ---> HTML (结合基础组件,事件系统,构件出页面结构)
相当于 ,行内标签,不会换行相当于,块级元素,会换行
数据绑定
{{ 数据 }}
运算 --> 表达式( 数值计算,字符串拼接,三元表达式)列表循环 (wx:for)wx:key绑定的是数组中的为唯一属性,wx:key=this表示数组是普通数组,`this`是循环项 索引: {{ index }} 名称: {{ item.name }}复制代码-标签 ---> 占位标签条件渲染(wx:if)(wx:if, wx:elif, wx:else) (hidden 属性是通过添加样式的方式来呈现的)当标签不是频繁的切换使用if,频繁切换使用hidden
事件绑定
获取事件源对象的值:
e.detail.value复制代码-
获取data中数据的值:
this.data.属性名复制代码-
将事件源对象的值设置回data中:
this.setData({ num: this.data.num + operation});复制代码-
事件绑定是不能直接传参,要通过自定义属性的方式传参( {{ 传递的参数}} ):
+ bandletap(e) { // console.log(e); const operation = e.currentTarget.dataset.operation; this.setData({ num: this.data.num + operation }); },复制代码-
样式
尺寸单位
当屏幕宽度等于 750px 时,1px = 1rpx
当屏幕宽度等于375px时, 1px =0.5rpx
样式导入只支持相对路径
选择器(微信小程序不支持通配符)
小程序的内置组件
小程序中常用的布局组件:
view,text,rich-text,button,image,icon,swiper,radio,checkbox等。复制代码-
view标签 相当于 p标签text标签 只能嵌套text标签 长按文字可以复制【selectable】(只有这个标签有这个功能) 可以对回车,空格进行编码 (decode)image标签 (打包上线的大小不能超过2M,使用图片的时候统一使用外网图片)图片存在默认的宽高(320px * 240px)mode 决定 图片内容 和 图片标签 做适配scaleToFill 默认值 不保持纵横比,拉伸至标签定义的宽高aspectFit 保持宽高比,保证图片的长边完全显示(常用 轮播图)aspectFill 短边完全显示widthFix 宽度不变,高度自动变化,保持原宽高比不变top,left,bottom,right 背景图定位小程序中的图片 直接支持 懒加载lazy-load 会自己判断 当图片出现在视口的上下三屏之内的时候,自己开始加载图片swiper标签 ---》 轮播图swiper高度 = swiper的宽度 * 图片的高度 / 原图的宽度 // 图片存在默认宽高 320 * 240 复制代码-navigator 导航组件 (块级元素,默认换行)复制代码-rich-text(富文本标签,将字符串解析成对应标签,相当于v-html)// 1 标签字符串// 2 对象数组复制代码-button 按钮大小(size:mini/default),颜色(type:default/primary/warn),是否镂空(plain),是否在文字前有加载loading(loading),开发能力(opentype)
开放能力(opentype):
小程序的生命周期
应用生命周期
触发过程:
onLaunch -》 onShow
App({ // 1 应用 第一次启用的时候触发 onLaunch() { // 在应用第一次启动的时候 获取用户信息 } // 2 应用 被用户看到的时候触发 onShow() { // 常用于小程序界面之间的切换 // 对应用的数据或者页面的效果进行重置 } // 3 应用 被隐藏的时候触发 onHide() { // 暂停或者清楚定时器 } // 4 应用 代码发生报错的时候 执行 onError() { // 在应用发生代码报错的时候,收集用户的错误信息,通过异步请求,将错误信息发送到后台去 } // 5 页面找不到的时候就会触发 // 应用第一次启动的时候,如果找不到第一个入口页面,才会触发 onPageNotFound() { // 如果页面不存在了 通过js的方式来重新跳转页面 重新跳转到第二个首页 // 不能跳转到tabbar页面 导航组件类似 wx.navigateTo({ url: "/pages/demo02/index" }) }})复制代码-
页面生命周期
onLoad -> onShow -> onReady
小程序自定义组件
步骤:
注意:
页面的.js文件中,存放事件回调函数的时候,存放在data同层级下组件的.js文件中,存放时间的回调函数的时候,存放在methods中在小程序中不要直接通过this.data.x.来修改数组的值(建议先拷贝一份数组,然后再对拷贝的数组进行修改)let tabs = JSON.parse(JSON.stringify(this.data.tabs));let tabs = this.data;复制代码-
组件之间的传值
父组件向子组件传值
通过 标签的属性来传递的:
父组件传递复制代码-子组件接收Component({ // 里面存放的是要从父组件中接收的数据 properties: { // 要接受的数据的名称 aaa:{ //type 接收数据的类型 type: String, //value 默认值 value: "" } }});复制代码-子组件使用父组件中传递过来的数据将接收过来的数据当作本身data中的数据来使用{{ aaa }}复制代码-
子组件向父组件传值
通过事件来传递的。
Tabs页面中:
{{ item.name }} // 占位符 传递的参数会替换掉 复制代码-
子组件的js文件中:(这样写不能改变组件内部的数据,只是基于样式的改变,不是基于功能)
methods: { hanldeItemTap(e) { // 获取索引 const {index} = e.currentTarget.dataset; // let {tabs} = this.data; // tabs.forEach((v,i) => i===index?v.isActive=true:v.isActive=false); // 修改data中的数据 // this.setData({ // tabs // }) // 触发父组件中的自定义事件同时传递给父组件 this.triggerEvent("itemChange", { index }) }}复制代码-
在父组件中的自定义组件中添加自定义事件:
1 2 3复制代码-
父组件的js中:
data: { tabs: [ { id: 1, name: "首页", isActive: true }, { id: 2, name: "待发货", isActive: false }, { id: 3, name: "待付款", isActive: false } ]}// 自定义事件 接收子组件传递的数据的handleItemChange(e) { // 接收传递过来的参数 const {index} = e.detail; // 拿到原数组 let {tabs} = this.data; tabs.forEach((v,i) => i===index?v.isActive=true:v.isActive=false); // 修改data中的数据 this.setData({ tabs })}复制代码-
其他属性
定义段 | 类型 | 描述 | |
---|---|---|---|
properties | Object Map | 组件的对外属性,是属性名,是属性设置的映射表 | |
data | Object | 常用于父组件向子组件传值,子组件接收父组件的值 | |
observers | Object | 监听properties和data的数据变化 | |
methods | Object | 组件的方法 | |
created | Function | 组件的生命周期函数(组件实例刚刚被被创建时执行)此时不能调用setData | |
attached | Function | 组件实例进入页面节点树时执行 | |
ready | Function | 组件布局完成时执行 | |
moved | Function | 移动执行 | |
detached | Function | 移除执行 | |
项目
首页商品列表购物车授权页面商品搜索商品收藏商品分类商品详情结算订单列表个人中心意见反馈
小程序的第三方框架
腾讯 wepy 类似于 vue美团 mpvue 类似于 vue京东 taro 类似于 react滴滴 chameleonuni-app 类似于 vue原生框架 MINA
使用阿里字体图标库
在阿里图标官网,将要使用的图标,加入购物车将图标,加入项目小程序 pyg ---》 Font class(通过类的方式来使用图标) ---》 查看在线链接在项目的styles文件夹中,创建iconfont.wxss文件打开链接,将链接中的内容复制到iconfont.wxss文件中使用字体图标库中的字体在全局wxss文件中,引入wxss文件@import "./styles/iconfont.wxss"复制代码-使用复制代码-
tabBar
在app.json中配置
tbaBar: { "color": "", //未选中的字体的颜色 "selectedColor": "", //选中后的字体的颜色 "backgroundColor": "", // 背景色 "position": "", //定位 "borderStyle": "", //边框样式 "list": [ { "pagePath": "", // 页面的路径 "text": "", // 标题的名称 "iconPath": "", // 未选中的图标路径 "selectedIconPath": "" // 选中后的图标的路径 } ]}复制代码-
页面样式的初始化
注意:在小程序中是不支持 通配符(*)的
在app.wxss文件中
page,view,text,swiper,swiper-item,image,navigator { padding: 0; margin: 0; box-sizing: border-box;}/* 主题颜色 1. less 中是存在 变量 的 2. 原生的css和wxss 也是支持 css的*/page { --themeColor: #eb4500; // 设计稿大小为 375px 时,1px = 2rpx,14px = 28rpx font-size: 28rpx;}复制代码-
使用主题颜色:
view { color: var(--themeColor);}复制代码-
头部
设置主题色:
"window": { "backgroundTextStyle": "light", // 字体颜色 "navigatorBarBackgroundColor": "#2b4500", // 背景色 "navigatorBarText": "唯品会", // 字体提示 "navigatorBarTextStyle": "white", // 字体样式 }复制代码-
使用接口数据
Page({ data: { swiperList: [] }, // 页面加载事件 onLoad: function() { /* 1. 发送异步请求 获取使用的数据 */ wx.request({ url: '', // 接口地址 success: (result) => { // 请求成功 给swiperList数组赋值 this.setData({ swiperList: result.data.message }) } }); /* wx.request异步请求太多了就会产生 回调地狱 的问题 解决方法: es6中的promise */ }})复制代码-
请求报错(两种解决方法):
在小程序 详情 界面 勾选上 不校验合法域名,web-view(业务域名),TLS版本以及HTTPS证书配置请求接口 见 8.7.将小程序请求的域名添加到后台
解决回调地狱的问题(es6的promise)
在项目的request文件夹中创建index.js文件
通过封装方法,然后调用函数传递参数的方式来使用
// 同时发送异步代码的次数let ajaxTime=0;export const request=(params) => { ajaxTime++; // 数据加载效果 wx.showLoding({ title: "加载中", mask: true }); return new Promise((resolve, reject) => { wx.request({ // 解构传递的参数 ...params, success: (result) => { resolve(result); }, faile: (err) => { reject(err); }, // 不管是成功还是失败都会调用这个函数 complete: () => { ajaxTime--; if(ajaxTime === 0) { // 关闭正在等待的图标 wx.hideLoading(); } } }); });}复制代码-
使用封装好的请求方法:
// 引入封装文件 (注意: 一定要把路径补全)import { request } from '../../request/index.js'; // 这里引入的是封装的request函数Page({ data: { swiperList: [] }, // 页面加载事件 onLoad: function() { /* 1. 发送异步请求 获取使用的数据 */ /* wx.request({ url: '', // 接口地址 success: (result) => { // 请求成功 给swiperList数组赋值 this.setData({ swiperList: result.data.message }) } }); */ /* wx.request异步请求太多了就会产生 回调地狱 的问题 解决方法: es6中的promise */ // 调用方法 this.getSwiperList(); }, // 调用封装好的方法 getSwiperList() { // 这里填充的数据会替换掉request方法中的...params, request({ url: 'htltps://api/zbtbs/home/swiperList'}); // 数据获取成功 .then (result => { this.setData({ swiperList: result.data.message }) }); }})复制代码-
将小程序请求的域名添加到后台
进入 微信公众平台开发开发设置服务器域名添加request合法域名
获取本地存储的数据
web中的本地存储 和 小程序中的本地存储的区别:
写代码的方式不一样web中:存储方式:localStorage.setItem("key", "value");获取方式: localStorage.getItem("key");小程序中:存储方式:wx.setStorageSync("key", "value");获取方式:wx.getStorageSync("key", "value");存的时候 有没有做类型转换web:不管存的数据是什么类型的数据,最后都会通过toString()方法转换为字符串类型的数据小程序:不存在数据的类型转换
// 接口返回的数据Cates: [],onLoad: function(options) { // 获取本地存储中有没有旧数据 const Cates = wx.getStorageSync("cate"); // 判断本地是否存在 if(!Case) { // 不存在 发送请求数据 this.setCates(); }else { // 有旧的数据 // 定义数据过期的时间 if(Date.now() - Cates.time > 1000 * 10) { // 重新发送请求 this.getCates(); } else { this.Cates = Cates.data; // 渲染数据 } }}// 获取请求的数据getCates() { // 把接口的数据存储到本地存储中 wx.setStorageSync("cates", {time:Date.now(),data: this.Cates});}复制代码-
定义公共的url
在request.js文件中,封装请求方法
export const request=(params) => { // 定义公共的url const baseUrl = "https://api.zbsb-/api/public" return new Promise((resolve, reject) => { wx.request({ // 解构传递的参数 ...params, url: baseUrl + params.url; success: (result) => { resolve(result); }, faile: (err) => { reject(err); } }); });}复制代码-
小程序支持es7的async语法
在微信开发者工具中勾选es6转es5语法在github里面-regenerator库中的runtime.js在小程序目录文件下新建文件夹/lib/runtime/runtime.js,将代码拷贝进去在每一个需要使用async语法的页面js文件中,引入文件import regeneratorRuntime from '../lib/runtime/runtime';复制代码-使用asyn语法:async getCates() { // 1 使用es7的async await来发送请求 const res=await request({url:"/categories"});}复制代码-
小程序url传参
// 传递参数// 拿取参数onLoad:function(options) { consol.log(options); // 打印输出options的值}复制代码-
封装tab切换组件
封装的Tab组件中:
使用封装的Tab组件:
滚动条触底事件(页面上滑事件)
滚动条触底,加载下一页数据
总页数 = Math.ceil(总条数 / 每页显示的数据数)
// 获取商品数据列表async getGoodsList() { const res=await request({url:"/goods/search",data:this.QueryParams}); // 获取总条数 const total = res.total; // 计算总页数 this.totalPage = Math.ceil(total / this.QueryParams.pagesize); // 拼接数组 this.setData({ goodsList: [...this.data.goodsList,...res.goods] }); // 关闭下拉刷新的窗口 wx-stopDownRefresh();}// 滚动条触底事件onReachBottom() { // 判断还有没有下一页数据 if(this.QueryParams.pagenum >= this.totalPage) { // 当前页码 > 总页数 没有下一页 } else { // 还有下一页 当前页码++ 重新发送请求 数据请求回来后要对data中的数组进行拼接 this.QueryParams.pagenum++; this.getGoodsList(); }}复制代码-
下拉刷新页面
触发下拉刷新事件(需要在页面的json文件中开启一个配置项)【enablePullDownRefresh: true,backgroundTextStyle: dark】重置 数据 数组重置页码 设置为1重新发送请求数据请求成功,手动关闭等待效果
onPullDownRefresh() { // 重置 数据 数组 this.setData({ goodsList: [] }); // 重置页码 设置为1 this.QueryParams.pagenum=1; // 重新发送请求 this.getGoodsList();}复制代码-
wx.showModel改变this的指向问题
wx.showModel({ title: '提示', content: '您是否要删除?', success :(res) => { ... }})复制代码-
js中的删除
cart.splice(index, 1); // 删除索引为index的元素cart.filter(v => v.checked); // 挑选出cart数组中checked为true的值复制代码-
弹窗的封装
在asyncWX.js文件中
export const showModel=({content}) => { return new Promise((resolve,reject) => { wx.showModel({ title: '提示', content: content, success :(res) > { resolve(res); }, fail :(err) => { reject(err); } }) })}复制代码-
使用
import {showModel} from '../../utils/asyncWx.js';async showTips() { const res=await showModel({content: '您是否要删除?'}) if(res.confirm) { cart.splice(index, 1); this.setData(cart); }}复制代码-
获取缓存中的数据
wx.getStorageSync("address");复制代码-
微信支付
企业账号在企业账号的小程序后台中 必须 给 开发者添加上白名单一个AppID可以绑定多个开发者绑定之后的开发者就拥有了开发者的权限了支付按钮先判断缓存中有没有token没有 跳转到授权页面 获取用户的 token 值有 执行支付操作
流程:创建订单,准备预支付,发起微信支付,查询订单
一,获取token
handleOrderPay() { try { // 1. 判断缓存中有没有token值 const token = wx.getStorageSync("token"); // 2. 判断 if(!token) { // 跳转到 授权 页面 wx.navigateTo({ url: "/page/auth/index" }) return; } // 3. 创建订单 // 准备创建订单需要的参数 const header = {Authorization:token}; // 准备请求体参数 const order_price = this.data.totalPrice; // 订单总价格 const consignee = this.data.address.all; // 详细地址 let goods = []; const cart = this.data.cart; goods.forEach(v => goods.push({ goods_Id: v.goods_Id, // 商品的id goods_number: v.goods_number, //商品数量 goods_price: v.goods_price // 商品的单价 })) const orderParams = {order_price,consignee,goods} // 4. 准备发送请求 创建订单 获取订单编号 const {order_number}=await request({url: "/order/create"},method:"POST",data:orderParams,head:head}); // 5. 发起 预支付接口 const {pay}=await request({url:"/order/req_unifiedorder",method:"POST",head,data:{order_number}}); // 6. 发起微信支付 await requestPayment(pay); // 7. 查询后台 订单状态是否成功 const res=await request(url:"/orders/chkOrder",method:"POST",head,data:{order_number}}); // 提示支付成功 await showToast({title:"支付成功"}); // 手动删除 缓存中支付成功购物车的数据 let newCart = wx.getStorageSync("cart"); // 过滤出没有被选中的数据 newCart = newCart.filter(v => !v.checked); wx.setStorageSync("cart",newCart); // 8.支付成功 跳转到订单页面 wx.navigateTo({ url: '/page/order/index' }) } catch(err) { await showToast({title:"支付失败"}); } }复制代码-
page/autn/index页面中:
获取授权复制代码-
// 获取用户信息// encryptedData // rawData// iv// signatureasync handleGetUserInfo(e) { try { // 获取用户信息 const { encryptedData,rawData,iv,signature } = e.detail; // 获取小程序登录之后的token值 在asyncWX.js中封装token请求方法 // wx.login({ // timeout: 1000, // success: (result) => { // cost { code } = result; // } // }) const {code} = await login(); const loginParams = { encryptedData, rawData, iv, signature, code } // 发送请求 获取用户的token const {token}=await request(url: '/user/wxlogin',data: loginParams,methods: "post"); // 将获取到的token存储到缓存中,同时跳转回上一个界面 wx.getStroageSync("token", token); wx.navigateBack({ data: 1 // 返回上一层 }) } catch(err) { console.log(err); }}复制代码-
在asyncWX.js文件中封装支付方法:
export const requestPayment=(pay) => { return new Promise((resolve,reject){ wx.request({ ...pay, success: (result) => { resolve(result); }, fail: (err) => { reject(err); } }) })}复制代码-
二,准备预支付(获取参数 pay)
三,发起微信支付(提交pay参数)
四,查询订单
五,删除缓存中已经被选中购买的商品
六,删除后的购物车数据 填充会缓存
七,跳转页面
图片上传(wx.uploadFile)
图片上传的时候,存储上传的图片的时候,要先拼接上之前的图片。
chooseImage:[],
this.setData({
chooseImage: [上传之前的图片组, 上传的图片组]
chooseImage: [...this.data.chooseImage, ...chooseImage]
})
上传文件的api不支持多个文件同时上传
解决方法:遍历数组 挨个上传
wx.uploadFile({ url: '', // 图片要上传到哪里 filePath: '', // 被上传文件的路径 name: '', // 上传的文件的名称 后台通过定义的上传的名称来获取名称 formData: {}, // 顺带的文本信息})复制代码-
项目发布
注意:发布之前记得关闭详情界面的 不校验合法域名
上传的每个文件大小不超过2M,总大小不超过10M。
上传:
版本号第一个数字(大版本的更新)第二个数字(重要功能更新)第三个数字(最小功能,小bug,小补丁)less文件是不会被打包上传的上传成功后的小程序还是一个体验版本的小程序,如果需要将体验版本的小程序变成线上版本的小程序,就在 微信公众平台将提交的体验本的小程序,提交审核(审核的时间大概是一个小时)。
相关免费学习推荐:微信小程序开发
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~