本文最后更新于:23 天前
前言 记录小程序开发过程中的问题。
文章内容
2025 年 7 月 3 日
点击跳转至文章页面。
1 2 3 4 5 6 7 8 9 <view src ="{{item.title}}" class ="post-item" bindtap ="postClick" data-title ="{{item.title}}" data-path ="{{item.path}}" > {{item.title}}</view >
1 2 3 4 5 6 7 8 postClick : function (option ) { var self = this ; var title = option.target .dataset .title var path = option.target .dataset .path wx.navigateTo ({ url : '../artical/artical?path=' + path, }) },
在 article.js 中,编写如下函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 onLoad : function (options ) { var self = this ; var markdownPath = options.path || '../../pages/artical/test2.md' ; wx.getFileSystemManager ().readFile ({ filePath : markdownPath, encoding : 'utf-8' , success (res ) { console .log ('Markdown内容:' , res.data ); let result = app.towxml (res.data , 'markdown' , { base : '/pages/article/' , theme : 'light' , }); self.setData ({ article : result, showLoading : false , articaleTitle : options.title || '默认标题' , }); }, fail (err ) { console .error ('读取文件失败:' , err); self.setData ({ showLoading : false }); wx.showToast ({ title : '加载失败' , icon : 'none' }); } }); },
文章内容展示。
1 2 3 <view class ="container" scroll-x ="true" > <towxml nodes ="{{article}}" /> </view >
这函数老是加载不到本地文件。
1 2 3 console .log ('options:' , options); var markdownPath = options.path || '../../pages/article/test.md' ;console .log ('最终路径:' , markdownPath);
小程序 - wx.getFileSystemManager().readFile 读取文件没有权限,需要怎么处理? - SegmentFault 思否
微信小程序中的文件系统 其实类似浏览器中Origin Private File System 的概念,它是供小程序使用的一块独立的文件区域,与代码文件和用户私有文件是独立的关系。你这里大概是想引用代码中的静态资源,是不能用这个 API 的。
本地文件指的是小程序被用户添加到手机后,会有一块独立的文件存储区域,以用户维度隔离。即同一台手机,每个微信用户不能访问到其他登录用户的文件,同一个用户不同 appId 之间的文件也不能互相访问。
艹。
1 2 3 4 5 6 7 8 const mdContent = require ("./test2.md.js" );console .log (mdContent);let result = app.towxml (mdContent, "markdown" , { base : "/pages/article/" , theme : "light" , });
1 2 3 4 5 6 7 8 9 10 11 Error: Input data should be a String at i.parse (VM8153 markdown.js:370) at i.render (VM8153 markdown.js:374) at module.exports (VM8152 index.js:56) at Rt.module.exports (VM8113 index.js:11) at Rt.<anonymous> (WASubContext.js?t=wechat&s=1751542853487&v=3.8.9:1) at li.onLoad (artical.js? [sm]:38) at li.<anonymous> (WASubContext.js?t=wechat&s=1751542853487&v=3.8.9:1) at li.c.__callPageLifeTime__ (WASubContext.js?t=wechat&s=1751542853487&v=3.8.9:1) at WASubContext.js?t=wechat&s=1751542853487&v=3.8.9:1 at WASubContext.js?t=wechat&s=1751542853487&v=3.8.9:1(env : Windows,mp,1.06.2407110; lib: 3.8.9)
towxml
是一个专为微信小程序设计的 富文本/Markdown 解析库 ,它能将 HTML 或 Markdown 内容转换为小程序支持的 WXML
结构。
1 2 3 4 let result = app.towxml (mdContent, "markdown" , { base : "/pages/article/" , theme : "light" , });
在 app.js 文件中:
1 2 3 4 5 6 App ({ towxml : require ('/towxml/index' ), ............................. )}
最终代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 onLoad : function (options ) { try { const mdModule = require ('../../pages/artical/test2.md.js' ); const mdContent = typeof mdModule === 'string' ? mdModule : mdModule.default || '' ; if (!mdContent) { throw new Error ('Markdown内容为空' ); } let result = app.towxml (mdContent, 'markdown' , { base : '/pages/article/' , theme : 'light' }); this .setData ({ article : result }); this .setData ({ showLoading : false }); } catch (err) { console .error ('解析失败:' , err); wx.showToast ({ title : '内容加载失败' , icon : 'none' }); } },
就这么直接把.md 转换成.js 文件不太妥当,只要文件里有代码块,整个文件就会报错,应为有符号冲突隔断的缘故。
博客列表
2025 年 7 月 2 日
构造模拟的博客文章列表数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 [ { "title" : "Hexo 博客搭建指南" , "url" : "2024/01/01/hexo-blog-guide/" , "date" : "2024-01-01" , "excerpt" : "从零开始搭建 Hexo 静态博客的完整教程,包含主题配置和部署到 GitHub Pages。" } , { "title" : "JavaScript 设计模式实践" , "url" : "2024/01/05/javascript-design-patterns/" , "date" : "2024-01-05" , "excerpt" : "单例模式、观察者模式等常见 JavaScript 设计模式的代码示例和应用场景。" } , { "title" : "CSS Grid 布局完全指南" , "url" : "2024/01/10/css-grid-layout/" , "date" : "2024-01-10" , "excerpt" : "通过实战案例学习 CSS Grid 布局的核心概念和高级技巧。" } , { "title" : "Node.js 性能优化策略" , "url" : "2024/01/15/nodejs-performance/" , "date" : "2024-01-15" , "excerpt" : "如何诊断和优化 Node.js 应用的 CPU、内存和 I/O 性能问题。" } , { "title" : "微信小程序开发踩坑记录" , "url" : "2024/01/20/wechat-miniprogram-tips/" , "date" : "2024-01-20" , "excerpt" : "分享开发微信小程序时遇到的 10 个常见问题及解决方案。" } , { "title" : "Python 数据可视化实战" , "url" : "2024/01/25/python-data-visualization/" , "date" : "2024-01-25" , "excerpt" : "使用 Matplotlib 和 Seaborn 制作专业级数据图表的步骤详解。" } , { "title" : "React Hooks 最佳实践" , "url" : "2024/02/01/react-hooks-best-practices/" , "date" : "2024-02-01" , "excerpt" : "如何避免滥用 useEffect 并合理组织自定义 Hook 的逻辑。" } , { "title" : "Git 高级用法备忘单" , "url" : "2024/02/05/git-advanced-tips/" , "date" : "2024-02-05" , "excerpt" : "rebase、cherry-pick 和 submodule 等 Git 高级功能的速查指南。" } , { "title" : "TypeScript 4.0 新特性解析" , "url" : "2024/02/10/typescript-4-features/" , "date" : "2024-02-10" , "excerpt" : "可变元组类型、标记元组元素等 TypeScript 4.0 重要更新详解。" } , { "title" : "Docker 容器化部署实践" , "url" : "2024/02/15/docker-deployment/" , "date" : "2024-02-15" , "excerpt" : "将 Node.js 应用容器化并通过 Docker Compose 管理多服务的完整流程。" } ]
数据字段说明
字段
示例值
作用
title
“Hexo 博客搭建指南”
文章标题
url
“2024/01/01/hexo-blog-guide/“
文章访问路径(需拼接域名)
date
“2024-01-01”
发布时间
excerpt
“从零开始搭建…”
文章摘要(可作简介)
小程序请求数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Page ({ data : { articles : [], }, onLoad ( ) { wx.request ({ url : "https://your-blog.com/articles.json" , success : (res ) => { this .setData ({ articles : res.data }); }, fail : (err ) => { console .error ("加载失败" , err); }, }); }, });
使用 require` 加载。
1 2 3 4 5 6 7 8 onLoad : function ( ) { const articles = require ('../../assets/data/articles.json' ); console .log ("------------------------------" ); console .log (articles); console .log (articles); },
1 2 3 4 5 6 7 8 9 10 11 12 [基础库] 正在使用灰度中的基础库 3.8.10 进行调试。如有问题,请前往工具栏-详情-本地设置更改基础库版本。Error : module 'assets/data/articles.json.js' is not defined, require args is '../../assets/data/articles.json' at q (WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1) at n (WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1) at li.onLoad (index .js? [sm]:15) at li.<anonymous> (WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1) at li.c.__callPageLifeTime__ (WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1) at WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1 at WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1 at WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1 at WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1 at WASubContext.js?t=wechat&s =1751451288428&v =3.8.10:1(env: Windows,mp,1.06.2407110; lib: 3.8.10)
JSON Online Validator and Formatter - JSON Lint
1 2 3 4 5 6 7 8 9 10 11 12 13 14 onLoad :function ( ) { wx.request ({ url : '../../assets/data/articles.json' , success : (res ) => { console .log ('原始数据:' , res.data ); const articles = Array .isArray (res.data ) ? res.data : []; this .setData ({ articles }); }, fail : (err ) => { console .error ('加载失败' , err); } }); },
1 index.js? [sm]:23 加载失败 {errno: 600009, errMsg: "request:fail invalid url " ../../assets/data/articles.json"" }errMsg: "request:fail invalid url " ../../assets/data/articles.json"" errno: 600009__proto__: Object(env : Windows,mp,1.06.2407110; lib: 3.8.10)
这个错误是因为 wx.request
不能直接使用本地相对路径 加载文件,它只能请求网络 URL。有三种解决方案:
改用 require
加载(推荐)
1 2 3 4 5 6 7 8 9 10 onLoad : function ( ) { try { const articles = require ('../../assets/data/articles.json' ); console .log ('加载成功:' , articles); this .setData ({ articles }); } catch (err) { console .error ('加载失败:' , err); } }
使用 wx.getFileSystemManager
读取本地文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 onLoad : function ( ) { const fs = wx.getFileSystemManager (); fs.readFile ({ filePath : 'assets/data/articles.json' , encoding : 'utf8' , success : (res ) => { try { const articles = JSON .parse (res.data ); this .setData ({ articles }); } catch (e) { console .error ('JSON解析失败:' , e); } }, fail : (err ) => { console .error ('文件读取失败:' , err); } }); }
filePath 必须是从项目根目录开始的相对路径,例如:
✅ assets/data/articles.json
❌ ../../assets/data/articles.json
将 JSON 文件托管到网络
1 2 3 4 5 6 wx.request ({ url : "https://你的域名.com/articles.json" , success : (res ) => { this .setData ({ articles : res.data }); }, });
需在小程序后台配置合法域名(设置 → 开发设置 → 服务器域名)
使用第二种方案,又出问题了:
1 2 [读取文件/文件夹警告] 无法读取 ../../assets/data/articles.json 文件或文件夹不在白名单中, 上传时会被忽略, 在真机上可能无法读取 index.js? [sm]:27 文件读取失败: {errMsg: "readFile:fail permission denied, open ../../assets/data/articles.json" }errMsg: "readFile:fail permission denied, open ../../assets/data/articles.json" __proto__: Object(env : Windows,mp,1.06.2407110; lib: 3.8.10)
他妈的,filePath
必须是从项目根目录开始的相对路径 ,不能使用 ../
向上跳转,并且小程序默认只能读取特定目录下的文件(如 assets
需手动配置
1 wx.getFileSystemManager ().readFileSync ("assets/data/articles.json" , "utf8" );
成功了,终极解决方法,重命名文件为 articles.js
,修改文件内容为:
1 2 3 4 5 6 7 8 9 10 module .exports = [ { title : "Hexo 博客搭建指南" , url : "2024/01/01/hexo-blog-guide/" , date : "2024-01-01" , excerpt : "从零开始搭建Hexo..." , }, ];
改用 require
加载:
1 2 3 4 5 6 7 8 9 10 onLoad : function ( ) { try { const articles = require ('../../assets/data/articles.js' ); console .log ('加载成功:' , articles); this .setData ({ articles }); } catch (err) { console .error ('加载失败:' , err); } },
刚才发现,博客上传至七牛云对象存储的所有图片,也就是博客站点的所有图片,都备份保存在了本机 C 盘里。
1 C :\Users\Lenovo\AppData\Roaming\Typora\typora-user-images
足足两千四百六十九张图片。
按需注入和用时注入 | 微信开放文档 (qq.com)
一切准备就绪,上传第一个体验版本,仅供测试,代码质量校验提醒需要启动按需注入。
1 "lazyCodeLoading" : "requiredComponents"
搞定了,在 app.json 文件中添加如上代码即可实现按需注入。
上传完成。
旧梦轻拾 初始化
2025 年 5 月 16 日
个人主体 :1 个邮箱只能绑定 1 个公众号或 1 个小程序。
Jiomeng 。
从零开始三天学会微信小程序开发(一)看到不少入门的小程序开发者不断的问重复性的问题,我们从实战角度开发了这个课程,希望能 - 掘金 (juejin.cn)
选择模板,绑定小程序唯一 appID 创建小程序,编译并预览。
在创建小程序的对话框中,输入项目名称(如 StudentComment),选择项目存放的目录,AppID 一栏填写你在微信小程序官方后台中获取到的 AppID,后端服务选择“不使用云服务”,模板选择“JS-基础模板”,然后点击“确认”按钮,创建小程序。
可选择二维码预览,手机微信扫码即可体验;也可选择自动预览,选择启动手机端自动预览/启动 PC 端自动预览,相当方便。
待编译成功,会自动弹出小程序的最终运行效果,如下图所示。
当我们开发好小程序之后,还需要把小程序上传到微信的服务器上。点击开发工具右上角的“上传”按钮,在弹出界面中输入更新类型、版本号和项目备注,然后点击上传,如下图所示。
如果代码不存在任何问题,很快就会弹出“代码上传成功”的提示框,表示上传成功。
上传成功后,我们回到微信小程序官方后台。点击“版本管理” 链接,可以看到上传的小程序版本。如下图所示。
2022 年 6 月 8 日后,未设置主营类目的帐号将无法提交代码审核。
点击“提交审核”按钮,按要求填写资料。完成之后,会在审核版本中看到刚刚申请的审核版本,如下图所示。
等到负责审核的工作人员通过之后,我们再执行最终的“发布”动作,我们开发的小程序才会出现在大众面前。
新页面
2025 年 5 月 16 日
小程序标题,修改 app.json 文件。
1 2 3 4 5 6 7 8 9 10 11 12 { "pages" : [ "pages/detail/detail" , "pages/index/index" ] , "window" : { "navigationBarTextStyle" : "black" , "navigationBarTitleText" : "社会脏话大全" , "navigationBarBackgroundColor" : "#ffffff" } , "style" : "v2" , "componentFramework" : "glass-easel" , "sitemapLocation" : "sitemap.json" , "lazyCodeLoading" : "requiredComponents" }
首页。
1 2 <view > 减轻您的工作,一键生成各种评语 </view > <view > <navigator url ="/pages/detail/detail" > 小学期末</navigator > </view >
奶奶的,多打了一个斜杠,老是报错,问 AI 也说不清道不明的。
1 <navigator url ="pages/index/index" > 小学期末 </navigator >
什么垃圾编译器。。。
2025 年 5 月 17 日
见鬼了,看来是直接粘贴代码携带隐藏符号了,亲手敲代码不会有报错。
1 2 3 4 5 <view class ="head" > 减轻您的工作,一键生成各种评语 </view > <view class ="links" > <navigator class ="btn" url ="/pages/detail/detail" > 脏话集锦 </navigator > </view >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 .head { display : flex; font-size : 36 rpx; justify-content : center; margin-top : 40 rpx; }.links { display : flex; justify-content : center; margin-top : 30 rpx; }.btn { border : 2px solid #5db59d ; padding : 20 rpx; border-radius : 20 rpx; font-size : 28 rpx; }
绑定数据。
1 2 3 4 5 6 7 data : { info : "减轻您的工作,一键生成各种评语" , links : ['轻度调侃' , '激烈宣泄' , '讽刺反讽' ] },
1 2 3 4 5 6 7 8 9 10 <view class ="links" > <navigator class ="btn" url ="/pages/detail/detail" wx:for ="{{links}}" wx:for-item ="link" > {{link}} </navigator > </view >
从零开始三天学会微信小程序开发(二)看到不少入门的小程序开发者不断的问重复性的问题,我们从实战角度开发了这个课程,希望能 - 掘金 (juejin.cn)
dist/Bmob-2.5.30.min.js · 元素(深圳)软件有限公司/hydrogen-js-sdk - Gitee.com
1 2 3 const Bmob = require ("/utils/Bmob-2.5.30.min.js" );Bmob .initialize ("你的Secret Key" , "你的API 安全码" ); wx.Bmob = Bmob ;
微信公众平台 (qq.com)
应用密钥 - Bmob 后端云 (bmobapp.com)
审核
2025 年 5 月 19 日
上周提交的小程序竟审核未通过。
测试代码不能提交。
应该写个开发日志。
库表设计:图片信息(图片名,图片链接,图片尺寸,图片分辨率,图片大小,标签)。
先写后端,核心接口:图片列表展示,图片详情信息,上传图片,下载图片。
再写前端,核心页面:图片列表,图片详情信息。
业务域名
2025 年 6 月 27 日
操作指南 / 业务域名配置 (qq.com)
微信小程序快速入门:从开发者工具到业务域名配置 (baidu.com)
操作指南 / 业务域名配置 (qq.com)
1 2 3 4 5 6 7 <scroll-view class ="scrollarea" scroll-y type ="list" > <view class ="container" > <web-view src ="https://deng-2022.atomgit.net/blog/" > </web-view > </view > </scroll-view >
微信开放文档 / 开发 (qq.com)
个人类型的小程序支持业务域名吗? (seowhy.com)
个人小程序支持业务域名吗? (apppark.cn)
2025 年 6 月 28 日
基础能力 / 网络 / 业务域名 (qq.com)
在管理后台配置业务域名
开发者登录小程序后台 mp.weixin.qq.com,选择开发管理->开发设置->业务域名,点击新增,按照要求配置业务域名。目前小程序内嵌网页能力暂不开放给个人类型账号和小游戏账号。
调用 web-view 组件实现小程序内嵌网页
在小程序管理后台成功配置业务域名后,才可使用 web-view 组件。小程序内调用 web-view 组件实现内嵌的网页,目前仅支持部分 jsapi 能力,关于 web-view 接口具体使用说明和限制,请 点击查看
界面设计
2025 年 7 月 1 日
小程序界面设计模板分享,前端开发进来看身处于网络世界日新月异的变革中,智能手机已然成为我们日常生活、学习和工作的必不可少 - 掘金 (juejin.cn)
微信开放社区 (qq.com)-订阅号的 appid 在哪里看?
存储桶列表 - 对象存储 - 控制台 (tencent.com)
微信现在对个人订阅号 的菜单跳转实行 「白名单+内容归属校验」 :
仅允许跳转至:
公众号后台的图文消息页面(mp.weixin.qq.com/...
)
已关联的小程序 (需开发者权限)
腾讯系域名(如 QQ 音乐、腾讯视频等)
完全禁止:
任何外部链接(即使备案、即使使用腾讯云 COS 中转)
GitHub Pages、自建博客、第三方平台链接
云服务器 ( Cloud Virtual Machine,CVM )为您提供安全可靠的弹性计算服务。
阿里云 ECS 是阿里云提供的弹性计算服务(Elastic Compute Service),一种可弹性伸缩的虚拟服务器。
微信公众平台跳转至外部链接,限制太死板了,简直不像是 5G 时代应该有的产物,毫无自由度。
PicMemories
2025 年 1 月 11 日
后端刚启动就报错,这么刺激:
1 2 3 4 5 6 Connected to the target VM, address: '127.0.0.1:10270' , transport: 'socket' 16:26:56.138 [main] DEBUG reactor.util.Loggers - Using Slf4j logging framework 16:26:56.142 [main] DEBUG reactor.core.publisher.Hooks - Enabling stacktrace debugging via onOperatorDebug 16:26:57.051 [main] ERROR org.springframework.boot.SpringApplication - Application run failed org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1 at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:218)
竟然又是配置文件带了中文,这么古老。
1 2 3 4 5 6 7 8 9 10 11 12 knife4j: enable: true openapi: title: PicMemories 接口文档 description: PicMemories 壁纸分享小程序 concat: 3348407547 @qq.com url: https://deng-2022.gitee.io/blog/ version: 1.0 license: Apache 2.0 group: test1: group-name: 壁纸分享
启动成功。
启动第一步,先把图床资源翻新下,前年用七牛云的临时域名,图片链接早都过期了。
这个小程序初步计划仅实现最核心的功能,即服务端上传图片,小程序端下载图片。
想起来当时是因为暑假那会儿有同学找我组队,说是需要一个会做小程序的,我从零开始边学边做,两周左右的时间就完善了基本页面。
后来这个同学就没有消息了,小程序也暂且搁置。
当时把页面分为四个板块:精选,分类,频道,我的,其实是想实现一个集交友,壁纸下载,聊天等的小程序。
不过没什么使用价值,连壁纸究竟该提供哪些分类和数量都没有想法,大部分编码时间里都在纠结图片间距和预览效果,其核心功能开发倒没多少进展。
直到昨天。
昨天下午我想起来那会儿确实也想要做一个个人网站,尝试学习不同领域的知识,小程序,Web,桌面端,保持学习的心态去实现心愿。
后来确实做到了,我成功运营起来自己的个人博客网站,相当成功。
昨天又想起来自己之前一直想搭建文档站点,后来还尝试开发过壁纸分享小程序,这两项工作也是时候该完成了。
文档站点,可以选择提炼出个人博客网站中的编程学习经验栏目;而壁纸分享小程序,则专门用来收录个人博客站点的精选壁纸图片。
初步打造属于自己的全生态软件集合。
时间还有很多,先执行起来吧。
小程序开发
2023 年 7 月 30 日
开发准备 HBuilderX+uni-app+uinCloud
微信开发者工具连接失败
微信开发者工具
最近在开发 PicMemories 壁纸分享小程序,浅浅记录遇到的一些问题
请求域名不合法
全局封装 request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 App ({ request (options ) { const { url, method, data, success, fail } = options; wx.request ({ url, method, data, success (res ) { success && success (res.data ); }, fail (error ) { fail && fail (error); }, }); }, onLaunch : function ( ) { console .log ("App launched" ); }, onShow : function ( ) { console .log ("App showed" ); }, onHide : function ( ) { console .log ("App hided" ); }, globalData : { userInfo : null , themeColor : "#F44336" , }, });
1 2 3 4 5 6 7 8 9 10 app.request ({ url : "http://localhost:8084/api/user/current" , method : "GET" , success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); }, });
1 Invalid character found in method name [0x160x030x010x020x000x010x000x010xfc0x030x031E0xe3]0x8eQ0xd60x0e0xf7mJ0x950x920x810xe00x0c0x820xb5)0xc70xdf0xefY0xe30xb8|0x9d0xd430xe50x8f5 ]. HTTP method names must be tokens
经排查,是因为把 http 写成 https 了:
数据双向绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <van-cell-group > <van-field required model:value ="{{username}}" label ="昵称" placeholder ="请输入昵称" /> <van-field required model:value ="{{phone}}" label ="密码" placeholder ="请设置密码" /> <van-field required model:value ="{{password}}" label ="手机号" placeholder ="请输入手机号" /> </van-cell-group >
1 2 3 4 5 data : { username : '' , password : '' , phone : '' },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 goToRegister ( ) { app.request ({ url : 'http://localhost:8084/api/user/register' , method : 'POST' , data : { username : this .data .username , password : this .data .password , phone : this .data .phone }, success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); } }) },
即可实现简单的双向数据绑定(2023/08/04 早)
生命周期函数 1 2 3 4 5 6 onLoad (options ) { },
1 2 3 4 5 6 onShow ( ) { Toast ("分类~" ) },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 onPullDownRefresh ( ) { },onReachBottom ( ) { },onShareAppMessage ( ) { }
路由跳转
1 wx.switchTab 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
1 wx.reLaunch 关闭所有页面,打开到应用内的某个页面
1 wx.redirectTo 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
1 wx.navigateTo 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
1 wx.navigateBack 关闭当前页面,返回上一页面或多级页面
我们可以分析出在不同的业务场景下,使用怎样的路由跳转更合适:
wx.switchTab:支持跳转至 tabbar 页面
跳转至 tabbar 页,关闭其他所有非 tabBar 页面
wx.redirectTo、wx.navigateTo:支持跳转至非 tabbar 页面
前者关闭当前页面,后者保留当前页面
wx.navigateBack:与 wx.navigateTo 配合,返回上一级页面
wx.reLaunch:支持跳转至任何页面
那么从登录页跳转至个人页,就应该用 wx.switchTab / wx.reLaunch(2023/08/05 早)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 goToLogin ( ) { app.request ({ url : 'http://localhost:8084/api/user/login' , method : 'POST' , data : { username : this .data .username , password : this .data .password , }, success : function (res ) { console .log (res) const data = res.data ; if (data.code == 0 ) { wx.setStorageSync ('sessionID' , res.header ["Set-Cookie" ]); Notify ({ type : 'success' , message : data.description }); wx.reLaunch ({ url : '/pages/user/index' }) } else { Notify ({ type : 'warning' , message : data.description }); } }, fail : function (error ) { console .log (error); } }) },
data 已初始化,未触发数据绑定 1 2 3 4 5 Page ({ data : { imgs : [], urlList : [] },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 onShow ( ) { Toast ("惊喜多多~" ) var _this = this app.request ({ url : 'http://localhost:8084/api/wallpaper/listPage' , method : 'GET' , success : function (res ) { const data = res.data ; _this.setData ({ 'imgs' : data.data .records }); _this.data .imgs .forEach ((item ) => { _this.data .urlList .push (item.wallpaperUrl ); }); }, fail : function (error ) { console .log (error); } }) },
1 2 3 <block class ="image-list" wx:for ="{{urlList}}" wx:key ="index" > <image class ="img" src ="{{item}}" alt ="刚刚" mode ="widthFix" /> </block >
这里的 image 标签,仍旧无法正常绑定到 urlList
当 show()生命周期函数未执行完毕,即 urlList 仍为空数组时,data 在页面展示时已经初始化
如此改造 show()生命周期函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 onShow ( ) { Toast ("惊喜多多~" ) this .getData (); },getData ( ) { var _this = this ; app.request ({ url : 'http://localhost:8084/api/wallpaper/listPage' , method : 'GET' , success : function (res ) { const data = res.data ; _this.setData ({ 'imgs' : data.data .records }); _this.setUrlList (); } }); },setUrlList ( ) { var urlList = []; this .data .imgs .forEach ((item ) => { urlList.push (item.wallpaperUrl ); }); this .setData ({ 'urlList' : urlList }); },
成功解决 urlList 数据双向绑定问题(2023/08/05 早)
无法获取 Session
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 goToLogin ( ) { app.request ({ url : 'http://localhost:8084/api/user/login' , method : 'POST' , data : { username : this .data .username , password : this .data .password , }, success : function (res ) { console .log (res) const data = res.data ; if (data.code == 0 ) { wx.setStorageSync ('sessionID' , res.header ["Set-Cookie" ]); Notify ({ type : 'success' , message : data.description }); wx.reLaunch ({ url : '/pages/user/index' }) } else { Notify ({ type : 'warning' , message : data.description }); } }, fail : function (error ) { console .log (error); } }) },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 app.request ({ url : 'http://localhost:8084/api/user/current' , method : 'GET' , header : { 'Content-Type' : 'application/json' , 'sessionID' : wx.getStorageSync ('sessionID' ) }, success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); } }) },
小程序登录 - 用户身份标识
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 goToLogin ( ) { var _this = this ; wx.login ({ success (res ) { if (res.code ) { console .log ("code = " + res.code ) wx.request ({ url : 'http://localhost:8084/api/user/login' , method : 'POST' , data : { code : res.code , username : _this.data .username , password : _this.data .password , }, success : function (res ) { console .log (res) const data = res.data ; if (data.code == 0 ) { Notify ({ type : 'success' , message : data.description }); wx.reLaunch ({ url : '/pages/user/index' }) } else { Notify ({ type : 'warning' , message : data.description }); } }, fail : function (error ) { console .log (error); } }) } else { console .log ('登录失败!' + res.errMsg ) } } }) },
1 2 private final String appId = "wxd12f7c79bd639a9b" ;private final String secret = "8a99ccc1802486c1387c1cda45288dd5" ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public String getCode2Session (String appId, String secret, String code) { String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code" , appId, secret, code); HttpRequest request = HttpRequest.get(url); log.info("result = " + request.execute()); return "request" ; } String url = "https://api.weixin.qq.com/sns/jscode2session" ; HashMap<String, Object> paramMap = new HashMap <>(); paramMap.put("appid" , appId); paramMap.put("secret" , secret); paramMap.put("js_code" , code); paramMap.put("grant_type" , "authorization_code" ); String result = HttpUtil.get(url, paramMap); log.info("result = " + result); return result;
1 2 Response Body: {"session_key" :"oZ0ju27QocpPhHF2Z1MrtQ==" ,"openid" :"otcWC6_yPHlB2Q6e0vIrB_J2iYHs" }
1 {"errcode" :40029,"errmsg" :"invalid code, rid: 64cf07f9-36a4c687-09c960f0" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 onShow () { Toast ('个人中心~' ); console .log ("seeesion_key = " + wx.getStorageSync ('session_key' )) app.request ({ url : 'http://localhost:8084/api/user/current' , method : 'GET' , header : { 'Authorization' : 'Bearer ' + wx.getStorageSync ('session_key' ) }, success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); } }) },
路由跳转、携带参数
1 2 3 4 5 6 7 8 9 10 11 onClickShow (e ) { const imageUrl = e.currentTarget .dataset .url ; const parameter = { url : imageUrl }; const url = '/pages/imageInfo/index?parameter=' + encodeURIComponent (JSON .stringify (parameter)); wx.navigateTo ({ url : url }); },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 onLoad (options ) { const {url} = JSON .parse (decodeURIComponent (options.parameter )); console .log (url) this .getData (url) },getData (url ){ this .setData ({ 'url' : url }) console .log (this .data .url ) },
要注意这里的 options 拿到的数据是封装好的对象,要使用如上方式接收参数:(2023/08/09 晚)
1 const { url } = JSON .parse (decodeURIComponent (options.parameter ));
点击 image 标签携带 URL
要给每个 <image>
标签添加 click 函数,以便点击不同的图片跳转到不同的页面,可以通过以下方法实现:
1 2 3 4 5 6 7 8 <image class ="img" src ="{{item}}" alt ="刚刚" mode ="widthFix" bindtap ="handleImageTap" data-url ="{{item}}" />
在当前页面的 JS 文件中定义 handleImageTap
方法来处理点击事件
可以使用 wx.navigateTo
方法跳转到不同的页面并传递参数
1 2 3 4 5 6 7 8 9 Page ({ handleImageTap (e ) { const imageUrl = e.currentTarget .dataset .url ; wx.navigateTo ({ url : `/pages/detail?imageUrl=\${imageUrl}` , }); }, });
在 handleImageTap
方法中,使用 e.currentTarget.dataset.url
获取到点击的图片链接,然后根据需要的逻辑进行不同的跳转。
请注意,上述代码是使用小程序原生的 wx.navigateTo
进行页面跳转,如果你使用的是框架或组件库,可能有不同的方法来实现页面跳转。(2023/08/09 晚)
实现点赞图片 1 2 3 4 5 6 7 8 <view class ="like" > <van-icon name ="{{isLiked ? 'like' : 'like-o'}}" color ="red" bindtap ="handleIconClick" /> </view >
1 2 3 4 5 6 7 8 9 10 11 handleIconClick ( ) { this .setData ({ isLiked : !this .data .isLiked , }); if (this .data .isLiked ){ Toast ("已收藏~" ) }else { Toast ('取消收藏~' ) } },
效果呈现
2024 年 4 月 22 日
半年前尝试开发过第一个微信小程序,花费了二十天时间认真做功能实现.。当时为了开发这个小程序,还借鉴了不少相关小程序的页面排版,多方参照才最终定型了这版页面。那么最终的效果如下 :
踩坑记录
首先,能够正确获取到小程序的 appID、appSecret:
开发者工具的 appID 必须设置正确,否则会不可避免地出现 invalid code 错误:(2023/08/06 早)
1 { "errcode" : 40029 , "errmsg" : "invalid code, rid: 64cf07f9-36a4c687-09c960f0" }
公众号开通
2024 年 4 月 22 日
今下午,我突然想要开通一个微信公众号,借此来激励我每天读书写作。那是因为最近开始慢慢回忆起小时候的乡村生活 ,写的东西渐渐多了起来。但总归是没时间没精力,写东西断断续续的,我对这样的写作现状很不满意。
于是下午看了很多相关公众号文章,计划近段时间就开启公众号文章写作计划:
我快速回顾了前段时间里了解到的有关微信公众平台的信息,包括小程序开发、智能机器人对话(动手做个 AI 机器人,帮我回消息!_牛客网 (nowcoder.com) )这些,把这些快遗忘的知识捡起来。
微信公众平台访问入口:微信公众平台 (qq.com)
注册一个微信公众号,选择订阅号 即可。
但接下来的一步就让我止步于此了,我必须要提供一个未被微信公众平台注册过 的邮箱
详细要求可以看这里:公众号注册提示“邮箱已被占用” (qq.com)
除了现在正在使用的 qq 邮箱外,去年写小程序时还用手机号申请了网易邮箱。但现在由于这个网易邮箱绑定了一个小程序,要想顺利开通微信公众号,目前只有两种解决办法:修改小程序登录邮箱 和注销小程序
虽然这个小程序是废稿,但毕竟是我开发的第一个微信小程序,未来可能还要继续优化呢。就这么注销了的话,本地的开发可能受到影响,怪可惜的。那最终的解决办法就是:今天晚上回去找我兄弟,让他注册一个网易邮箱,完事了我把小程序邮箱账号更换成他的,我开通的微信公众号就绑定我的网易邮箱吧。
那么现在就开始研究研究今年年初搞过的微信智能 AI 机器人了,不知道当时怎么想的,竟然没有记录下代码是如何起来的。相关的开发文档也没有多少记录,只有运行效果,只好是我再继续摸索摸索。
2024 年 4 月 23 日
很好,昨天下午总结了一番微信智能 AI 机器人的开发流程,晚上又让我的好兄弟注册了新的网易邮箱。
这下我就成功开通了微信公众号了。
总结