- 微信小程序前端开发踩坑——引入weui组件库
前言 今天在写微信小程序前端页面,想引入weui组件库来完成开发。结果按着官方文档来遇到了一堆问题,最后靠着不断百度查资料才最终解决。所以将过程记录一下,避免后面再遇到这类坑。 注意:本文默认读者已知道怎么使用npm 1. 初始化 以管理员身份运行命令行窗口(cmd),在cmd中进入项目的根目录。然后输入以下命令: [代码]npm init [代码] 后面一路按回车健即可,最终会在项目的根目录中创建出一个名为package.json的文件。 2. 安装weui组件库 在cmd中紧接着输入以下命令: [代码]npm install weui-miniprogram [代码] 命令执行完毕后会多出来一个node_modules文件夹,里面包含了weui组件库。 3. 构建npm 在微信开发者工具中,选择“工具”->“构建npm”。如无意外会出现类似“没有找到可以构建的NPM包……”这样的报错。 这时就需要在项目根目录找到package.config.json文件,修改相关的配置如下: [代码]{ ... "setting": { ... "packNpmManually": true, "packNpmRelationList": [ { "packageJsonPath": "./package.json", "miniprogramNpmDistDir": "./" } ] } } [代码] 继续在开发者工具中的“详情”->“本地设置”里检查是否勾选上“使用npm模块”选项,若没勾选则勾选上。 完成上述配置后,重新构建npm,即可构建完成。 4. 重启项目 在开发者工具中“项目”->“重新打开此项目”,完成对项目的重启。 注意:这一步非常重要!!!否则引入组件会提示找不到文件!!! 5. 引入wxss 在app.wxss中,引入weui库的wxss文件 [代码]@import 'miniprogram_npm/weui-miniprogram/weui-wxss/dist/style/weui.wxss'; [代码] 引入时要根据实际情况调整路径,但最长后缀均为 [代码]/weui-miniprogram/weui-wxss/dist/style/weui.wxss [代码] 6. 引入组件 在想要使用组件的页面对应的js文件中,对组件进行的引入。一定要注意自己项目的目录结构!!! [图片] 而官方文档的写法是 [图片] 如果直接照搬官方文档的写法,则忽略了目录结构,会报错!! 接着在要使用组件的页面对应的wxml文件中使用该组件即可 [代码]<mp-dialog title="test" show="{{true}}" bindbuttontap="tapDialogButton" buttons="{{[{text: '取消'}, {text: '确认'}]}}"> <view>test content</view> </mp-dialog> [代码] 效果如下: [图片] 后记 不得不说,前端开发的坑实在是太多了,上面记录的过程我摸索了一个多小时。看来平时一定要多注意总结才行,不然真的非常消耗时间!!! 创作不易,觉得有用麻烦点个赞,谢谢~~~
2022-01-11 - 【实战】微信小程序云开发中,使用TcbRouter路由模块在一个云函中解决多个业务逻辑
最近在做自己的小程序《看啥好呢》,这个小程序是使用云开发的方式开发的,功能特别简单,就是获取豆瓣、大麦网的数据展示,虽然功能简单,但还是记录下开发过程和一些技术点,大约会有两篇博文产出,这是第二篇。GitHub 地址 [图片] 在上一篇《实战:在小程序中获取用户所在城市信息》中,介绍了如何获取用户所在城市,这一篇就介绍一下小程序云函数开发的一些东西。 项目结构 小程序《看啥好呢》全部数据都来自豆瓣网和大麦网,整个项目结构如下 [图片] 电影、电视模块下的每个分类,只是改变豆瓣网同一个接口某个字段即可,本地好看模块是拿的大麦网的接口,而电影详情页是使用 Cherrio 实现豆瓣电影详情页网页解析拿到的数据。 项目目录结构 [图片] 项目开发 由于电影、电视列表模块用的都是同一个接口,只是某些参数不同,而详情页是解析网页方式,不是走的接口,所以处理逻辑与列表不相同,怎么样在一个云函数中处理不同的逻辑呢。 从上面的项目目录结构可以看出,我为整个项目只划分了两个云函数,分别是 damai 和 douban,在 damai 中处理来自大麦网的数据,douban 中处理来自豆瓣的数据。 Router 模块 在前端中,Router 可以处理不同的请求分支,于是在云函数中也可以使用 Router,下面使用了 tcb-router,它是一个基于 koa 风格的小程序·云开发云函数轻量级类路由库,主要用于优化服务端函数处理逻辑。 douban/index.js [代码]// 云函数入口文件 const cloud = require("wx-server-sdk"); const TcbRouter = require("tcb-router"); cloud.init(); // 云函数入口函数 exports.main = async (event, context) => { const app = new TcbRouter({ event }); /** 查询列表 */ app.router("list", async (ctx, next) => { const list = require("./list.js"); ctx.body = list.main(event, context); }); /** 查询详情 */ app.router("detail", async (ctx, next) => { const detail = require("./detail.js"); ctx.body = detail.main(event, context); }); return app.serve(); }; [代码] 云函数目录结构如下 [代码]/douban ----/node_modules ----index.js ----list.js ----detail.js ----package.json [代码] HTTP 请求 HTTP 请求方面,小程序云函数中常用的是 request-promise,它是一个 Promise 分格的 HTTP 请求库,使用它还必须安装它的依赖,两个包都要安装 [代码]npm install --save request npm install --save request-promise [代码] 下面看看电影列表是怎么处理的,douban/list.js [代码]const rp = require("request-promise"); exports.main = async (event, context) => { const type = event.type; const tag = encodeURI(event.tag); const limit = event.limit || 50; const start = event.start || 0; const options = { uri: `https://movie.douban.com/j/search_subjects?type=${type}&tag=${tag}&page_limit=${limit}&page_start=${start}`, headers: { Host: "movie.douban.com", Referer: "https://movie.douban.com/", }, json: true, }; return rp(options) .then((res) => res) .catch((err) => { console.log(err); }); }; [代码] 请求参数都放在 event 当中,在调用云函数的时候传递,下面是电影列表页面调用云函数的代码 [代码]let { id, type } = this.data; wx.cloud .callFunction({ name: "douban", data: { $url: "list", type, tag: id == "hot" ? "热门" : "最新", }, }) .then((res) => { const result = res.result; this.setData( { dataList: result.subjects, }, () => { wx.hideLoading(); } ); }) .catch((err) => { console.log(err); wx.showToast({ title: "出错了", icon: "none", }); wx.hideLoading(); }); [代码] 从调用云函数的 data 属性中的第一个参数 [代码]$url[代码] 是请求的路由,第二个参数开始即是请求需要的参数。 Cherrio 实现详情页解析 cheerio 是一个 jQuery Core 的子集,其实现了 jQuery Core 中浏览器无关的 DOM 操作 API,以下是一个简单的示例: [代码]var cheerio = require("cheerio"); // 通过 load 方法把 HTML 代码转换成一个 jQuery 对象 var $ = cheerio.load('<h2 class="title">Hello world</h2>'); // 可以使用与 jQuery 一样的语法来操作 $("h2.title").text("Hello there!"); $("h2").addClass("welcome"); console.log($.html()); // 将输出 <h2 class="title welcome">Hello there!</h2> [代码] 简单来说,cheerio 就是服务器端的 jQuery,去掉了 jQuery 的一些效果类和请求类等等功能后,仅保留核心对 dom 操作的部分,因此能够对 dom 进行和 jQuery 一样方便的操作。它是我们筛选数据的利器——把多余的 html 标签去掉,只留下我们想要的内容的重要工具。需要注意的是,cheerio 并不支持所有 jQuery 的查询语法,比如 [代码]$('a:first')[代码] 会报错 ,只能写成 [代码]$('a').first()[代码] ,在使用的时候需要注意。 下面是电影、电视的详情页处理逻辑 [代码]const rp = require("request-promise"); const cheerio = require("cheerio"); exports.main = async (event, context) => { const subjectId = event.id; const baseUrl = "https://movie.douban.com/j"; const options = { uri: `${baseUrl}/subject_abstract?subject_id=${subjectId}`, headers: { Host: "movie.douban.com", Referer: "https://movie.douban.com/", }, json: true, }; return rp(options) .then((res) => { return rp( `https://movie.douban.com/subject/${subjectId}/` ) .then((html) => { const $ = cheerio.load(html); const plot = $("#link-report") .find("span") .text(); //.replace(/\s/g, '') res.subject.plot = plot; return res; }) .catch((err) => { console.log(err); }); }) .catch((err) => { console.log(err); }); }; [代码] 完整源码已开源 GitHub,是一个很好的学习项目。
2020-12-23 - 云开发实战-如何维护用户表?(优化版)
前言 之前写过一篇《云开发-如何维护用户表?》,这种方式是最简单的,经过阅读了一些开源项目的代码,我优化了部分写法。 对比 优化前实现思路: 通过 login 云函数获取 openid 存放到本地 在授权信息的时候去添加 userInfo 根据 openid 去查询是否已经存储 没有查到就是新用户进行添加并存放 id 到本地 查看后老用户就根据 id 进行更新信息 优化后实现思路: 在 app.js 通过 queryCurrentUser 云函数查询 openid 是否在用户表 得到状态后存放在 app.js 的全局变量 authorized 属性里面 当需要用户授权的时候判断状态,没有就跳转到授权页面 进行授权调用 authorize 云函数添加用户 代码 在 app.js 通过 queryCurrentUser 云函数查询 openid 是否在用户表 得到状态后存放在 app.js 的全局变量 authorized 属性里面。 [代码]wx.cloud.callFunction({ // 云函数名称 name: 'user', // 传给云函数的参数 data: { action: 'queryCurrentUser' } }).then(res => { if (res.result.errMsg === 'user.query.ok') { this.onAuthorized(res.result.data.userInfo); this.authorized = true; } wx.hideLoading(); }) onAuthorized(userInfo) { this.authorized = true; this.globalData.userInfo = userInfo; }, [代码] queryCurrentUser 云函数 [代码]async queryCurrentUser(context, params) { const { OPENID } = context; let res = await db.collection('users').where({ openid: OPENID }).get(); if (res.data.length === 0) { return { errMsg: 'user.query.none' }; } return { errMsg: 'user.query.ok', data: { userInfo: res.data[0].userInfo } }; }, [代码] 当需要用户授权的时候判断状态,没有就跳转到授权页面 index.js [代码]toInfo(res) { if (app.authorized !== true) { wx.navigateTo({ url: '/pages/authorize/authorize' }); return; } // 省略业务代码.... } [代码] 进行授权调用 authorize 云函数添加用户 authorize.js [代码]wx.cloud.callFunction({ // 云函数名称 name: 'user', // 传给云函数的参数 data: { action: 'authorize', userInfo: userInfo } }).then(res => { if (res.result.errMsg === 'user.authorize.ok' || res.result.errMsg === 'user.authorize:authorized') { app.onAuthorized(res.result.data.userInfo); wx.showLoading({ title: '授权成功' }); setTimeout(() => { wx.hideLoading(); app.navigateBack(); }, 1000); return; } wx.nextTick(() => { wx.showToast({ title: '授权失败', icon: 'none', duration: 1000 }); }); }); [代码] authorize 云函数 [代码]const authorizedRes = { env: cloud.DYNAMIC_CURRENT_ENV, errMsg: 'user.authorize:authorized' }; async authorize(context, params) { const { OPENID } = context; let getRes = await db.collection('users').where({ openid: OPENID }).get(); if (getRes.errMsg !== 'collection.get:ok') { return errorAuthorizeRes; } if (getRes.data.length > 0) { return authorizedRes; } let addRes = await db.collection('users').add({ data: { openid: OPENID, userInfo: params.userInfo, authorizedTime: new Date(), } }); return { errMsg: 'user.authorize.ok', data: { userInfo: params.userInfo } }; } [代码] 总结 这种方式优点如下: 用云函数来验证,云函数可以直接获取 openid 通用统一的授权页面进行授权,这样就不需要在不同的地方写同样的授权代码 添加逻辑在云函数中实现,改小程序前端代码需要重新发版,云函数部署就行 代码需要不断优化才能更好。
2020-09-16