- Node.js + express + access-db 轻松实现小程序全栈开发(上)
本次教程,只是给大家抛砖引玉,适合新手。只要你懂js,那你就会全栈! 1.新建小程序项目 如下,我们打开微信开发者工具,并创建一个名为[代码]test[代码]的小程序项目,项目在[代码]mini[代码]目录下面。 [图片] 创建完成之后,会生成一个初始代码,如下: [图片] 2.新建express项目 在上面小程序项目目录[代码]mini[代码]的同级目录里面,新建一个[代码]server[代码]目录,并在该目录下,打开命令窗 [图片] 在命令窗执行以下命令,创建项目 [代码]# 初始化项目,然后一直回车就可以了 npm init # 安装express npm install express # 生成express项目模板,选择y npx express-generator # 安装项目依赖 npm install [代码] 完成后,项目代码如下结构 [图片] 其中,我们目前只需要写接口,所以只需要在[代码]routes[代码],[代码]app.js[代码]里面进行操作。 此时,执行 [代码]npm run start[代码] 启动服务器,访问[代码]http://localhost:3000[代码]出现如下界面,说明成功了。 [图片] 3.安装mysql或mongodb mysql或mongodb你可以任意选择一种,不影响后面的基础教学 mysql安装:如果你只是为了方便学习,建议安装mysql5.7版本的,8.0版本的密码类型,目前node还不支持,需要你改配置。所以,如果你不想折腾,可以就选择5.7。安装好之后,我们就可以通过数据库可视化工具连接它,如下 [图片] 连接成功后,我们新建一个[代码]test[代码]数据库,其他两个选项,就默认即可 [图片] mongodb安装:我这里就不写了,和mysql差不多的步骤。 4.创建表anime 如图,创建一张存储动漫信息的简单表,其中[代码]id[代码]一定要设置成自动递增 [图片] 5.后台接口 在之前新建的项目目录[代码]server[代码]下面,安装[代码]access-db[代码]和[代码]dotenv[代码] [代码]npm install access-db npm install dotenv [代码] 1).在[代码]app.js[代码]的最前面引入[代码]dotenv[代码],如下: [代码]require('dotenv').config() var createError = require('http-errors'); var express = require('express'); ... [代码] 2).在项目根目录,新建[代码].env[代码],并配置数据想着信息。如果你是mongodb就配置mongodb的想着信息,详细配置,请看access-db文档 [代码]MYSQL_HOST=localhost MYSQL_USER=root MYSQL_PASSWORD=123456 MYSQL_PORT=3306 MYSQL_DATABASE=test //要使用的哪个数据库 [代码] 3).在[代码]/routes[代码]目录下,新建[代码]anime.js[代码]路由,代码如下: [代码]var express = require('express'); var routerAnime = express.Router(); /* GET users listing. */ routerAnime.get('/', function(req, res, next) { res.send('anime api'); }); module.exports = routerAnime; [代码] 4).在[代码]app.js[代码]中引入上面的路由: [代码]... var animeRouter = require('./routes/anime') var app = express() ... app.use('/anime', animeRouter) [代码] 最后大概就是这个样子 [图片] 这个时候,你启动项目,再在浏览器里打开[代码]http://localhost:3000/anime[代码],就会出现如下信息。此时,一个简单的接口,就完成了。 [图片]
2021-07-04 - 微信小程序开发搜索功能(前端+后端+数据库)
[图片] 超级简单的界面,表单,提交按钮,搜索结果展示区域... 下面是index.wxml [代码]<!--index.wxml-->[代码][代码]<[代码][代码]form[代码] [代码]bindsubmit[代码][代码]=[代码][代码]"formSubmit"[代码][代码]>[代码][代码]<!--提交按钮 -->[代码][代码]<[代码][代码]input[代码] [代码]type[代码][代码]=[代码][代码]"text"[代码] [代码]name[代码][代码]=[代码][代码]"id"[代码] [代码]placeholder[代码][代码]=[代码][代码]'输入关键词'[代码] [代码]style[代码][代码]=[代码][代码]'border:1px solid #ccc;height:30px;'[代码][代码]/>[代码][代码]<[代码][代码]button[代码] [代码]formType[代码][代码]=[代码][代码]"submit"[代码] [代码]class[代码][代码]=[代码][代码]"btn"[代码][代码]>搜索</[代码][代码]button[代码][代码]> [代码][代码]</[代码][代码]form[代码][代码]>[代码][代码]<[代码][代码]view[代码][代码]>搜索结果</[代码][代码]view[代码][代码]>[代码][代码]<[代码][代码]view[代码] [代码]wx:for[代码][代码]=[代码][代码]"{{re}}"[代码] [代码]wx:key[代码][代码]=[代码][代码]"re"[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]style[代码][代码]=[代码][代码]'color:#f00;'[代码][代码]>{{item.result}}</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]style[代码][代码]=[代码][代码]'color:green;'[代码][代码]>{{item.title}}</[代码][代码]view[代码][代码]>[代码][代码]</[代码][代码]view[代码][代码]>[代码] *跟前端差不多,form表单要加一个bindsubmit="formSubmit" 接着就是index.js [代码]//index.js[代码][代码]//获取应用实例[代码][代码]const app = getApp()[代码][代码]Page({[代码][代码] [代码][代码]/**[代码][代码] [代码][代码]* 页面的初始数据[代码][代码] [代码][代码]*/[代码][代码] [代码][代码]data: {[代码][代码] [代码][代码]result:[代码][代码]''[代码][代码],[代码][代码] [代码][代码]state:[代码][代码]''[代码][代码] [代码][代码]},[代码][代码] [代码][代码]formSubmit: [代码][代码]function[代码] [代码](e) {[代码][代码] [代码][代码]var[代码] [代码]that = [代码][代码]this[代码][代码];[代码][代码] [代码][代码]var[代码] [代码]formData = e.detail.value.id; [代码][代码]//获取表单所有name=id的值 [代码][代码] [代码][代码]wx.request({[代码][代码] [代码][代码]url: [代码][代码]'http://localhost/2018-5-24/search.php?id='[代码] [代码]+ formData,[代码][代码] [代码][代码]data: formData,[代码][代码] [代码][代码]header: { [代码][代码]'Content-Type'[代码][代码]: [代码][代码]'application/json'[代码] [代码]},[代码][代码] [代码][代码]success: [代码][代码]function[代码] [代码](res) {[代码][代码] [代码][代码]console.log(res.data)[代码][代码] [代码][代码]that.setData({[代码][代码] [代码][代码]re: res.data,[代码][代码] [代码][代码]})[代码][代码] [代码][代码]wx.showToast({[代码][代码] [代码][代码]title: [代码][代码]'已提交'[代码][代码],[代码][代码] [代码][代码]icon: [代码][代码]'success'[代码][代码],[代码][代码] [代码][代码]duration: 2000[代码][代码] [代码][代码]})[代码][代码] [代码][代码]}[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},[代码][代码]})[代码] 为了方便大家研究,我把后端的php源码也贴出来。 search.php [代码]<?php[代码][代码]header([代码][代码]"Content-type:text/json;charset=utf8"[代码][代码]);[代码][代码]//定义参数[代码][代码]$id[代码] [代码]= [代码][代码]$_GET[代码][代码][[代码][代码]"id"[代码][代码]];[代码][代码]//表单验证[代码][代码]if[代码][代码]([代码][代码]empty[代码][代码]([代码][代码]$id[代码][代码])){[代码][代码] [代码][代码]echo[代码] [代码]"[{\"result\":\"表单为空...\"}]"[代码][代码];[代码][代码]}[代码][代码]else[代码][代码]{[代码][代码] [代码][代码]//连接数据库[代码][代码] [代码][代码]$con[代码] [代码]= mysql_connect([代码][代码]"数据库链接"[代码][代码],[代码][代码]"账号"[代码][代码],[代码][代码]"密码"[代码][代码]);[代码][代码] [代码][代码]//设置数据库字符集 [代码][代码] [代码][代码]mysql_query([代码][代码]"SET NAMES UTF8"[代码][代码]);[代码][代码] [代码][代码]//查询数据库[代码][代码] [代码][代码]mysql_select_db([代码][代码]"数据库名"[代码][代码], [代码][代码]$con[代码][代码]);[代码][代码] [代码][代码]$result[代码] [代码]= mysql_query([代码][代码]"SELECT * FROM test WHERE id like '%$id%'"[代码][代码]);[代码][代码] [代码][代码]$results[代码] [代码]= [代码][代码]array[代码][代码]();[代码][代码] [代码][代码]while[代码][代码]([代码][代码]$row[代码] [代码]= mysql_fetch_assoc([代码][代码]$result[代码][代码]))[代码][代码] [代码][代码]{[代码][代码] [代码][代码]$results[代码][代码][] = [代码][代码]$row[代码][代码];[代码][代码] [代码][代码]}[代码][代码] [代码][代码]// 将数组转成json格式[代码][代码] [代码][代码]echo[代码] [代码]json_encode([代码][代码]$results[代码][代码]);[代码][代码] [代码][代码]//关闭数据库连接[代码][代码] [代码][代码]mysql_close([代码][代码]$con[代码][代码]);[代码][代码]}[代码][代码]?>[代码] *数据库表名为test,里面一共有两个字段,一个是id,一个是title 所以index.wxml里面有两个值 [代码]<[代码][代码]view[代码] [代码]wx:for[代码][代码]=[代码][代码]"{{re}}"[代码] [代码]wx:key[代码][代码]=[代码][代码]"re"[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]style[代码][代码]=[代码][代码]'color:#f00;'[代码][代码]>{{item.result}}</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]style[代码][代码]=[代码][代码]'color:green;'[代码][代码]>{{item.title}}</[代码][代码]view[代码][代码]>[代码][代码]</[代码][代码]view[代码][代码]>[代码] wx:for="{{re}}"指的是循环数组,在js代码中,我们把所有服务端取得的数据,存进了re的数组 然后,{{item.result}}指的是服务端返回表单为空的结果。{{item.title}}返回的是搜索结果,这个结合你的数据库吧,你想展示什么结果,你就把title改成你数据库的相关字段。 [图片]
2018-07-26 - 业务域名设置--校验文件检查失败自查指引
目前不少开发者在设置业务域名时,发现检查校验文件失败,可先按照如下步骤进行自查: 如果想保存的业务为https://test.com/,下载下来的校验文件为AbC.txt,则需要确保https://test.com/AbC.txt能够访问。 校验文件内容错误。校验文件内容一般是非HTML数据,如果下载下来的校验文件内容为HTML数据,一般为登录态过期。请重新登录小程序下载校验文件。 使用4G网络尝试访问链接,确认自身服务器没有拦截请求(常见于设置了白名单或者防火墙的服务器,需开发者自行确认下) https证书过期。请确保https证书处于有效期内。 使用curl 测试链接,确保curl能够正常访问链接,且curl出来的内容为校验文件内容。 使用time curl https://test.com/abc.txt查看链接时间,建议耗时在1s之内。 请确保url中的文件名与下载下来的文件名大小写一致。如下载的文件是AbC.txt,确保url是https://test.com/AbC.txt,不能是https://test.com/abc.txt 部分用户的服务器配置较陈旧,安全性差(如配置 768位 的 DH),为了保证通信安全,微信后台不支持,请更新服务器配置。 (1)通过https://cloud.tencent.com/product/tools#userDefined12,检测网址是否支持TLS1.2。 (2)可通过工具 https://www.ssllabs.com/ssltest/analyze.html 检查自己的服务器,对该工具标红的各项漏洞逐项修补,建议更新配置直到该工具打分为 C及以上 。 9. 如上述检查都没有问题,请重新下载校验文件重试,确保上传到服务器的文件内容与新下载的文件内容一致。
2018-06-21 - 小程序云开发发送短信,接收不到测试消息。换了三个接收号码,也收不到?
发送返回信息 [图片] 小程序企业已经认证 [图片] 短信资源包也是新买 [图片] 是怎么回事??
2023-01-16 - openapi.cloudbase.sendSms 发送短信长时间收不到?
使用openapi.cloudbase.sendSms 发送短信的失败率特别高,各位亲有没有遇到过这种问题呢。 [图片]
03-16 - 【笔记】横向滑动列表的渲染
前言 今天在学习列表渲染的时候,尝试实现了支持横向滑动的列表,但是遇到了很多问题,做一个小小的总结。 组件scroll-view scroll-view是一种视图容器,指定可滚动视图区域。通过设置属性scroll-y=true并给给scroll-view一个固定高度height,可以实现竖向滚动;通过设置属性scroll-x=true可以实现横向滚动,其他的属性可以参考官方文档。 列表渲染 列表渲染是一种很基础的渲染方法,在组件上使用 wx:for 绑定一个数组,即可使用数组中各项的数据重复渲染该组件。在组件中,使用 wx:for-item 可以指定数组当前元素的变量名,默认为item;使用 wx:for-index 可以指定数组当前下标的变量名,默认为index;使用 wx:key 来指定列表中项目的唯一的标识符,可以提高渲染效率(没有特殊需求的话可以直接用index指定)。 例如,在.js中声明一个含有六个元素的数组list,可以用以下代码循环地渲染list中的所有元素 [代码]<!-- index.wxml 列表渲染 --> <view wx:for="{{list}}" wx:key="{{index}}" class="view-parent"> <view class="view-item">{{item.txt}}</view> </view> [代码] 显示效果如下: [图片] 横向滑动列表 将组件scroll-view和列表渲染结合,就可以实现横向滑动列表了,样例代码如下: [代码]<!-- index.wxml 横向滑动列表 --> <text style="margin-left: 40%;">横向滑动列表</text> <scroll-view scroll-x="true" class="scroll-x-list"> <view wx:for="{{list}}" wx:key="{{index}}" class="view-parent"> <view class="view-item">{{item.txt}}</view> </view> </scroll-view> /* index.wxss */ .scroll-x-list{ height:150px; } .view-item{ width:100px; height:100px; background:#1bf891; margin:10px; } [代码] 显示效果如下: [图片] 可以看到结果和预期差很多,不仅没有实现横向滑动,还没有显示出所有的元素。原因是代码虽然在组件中设置了需要的属性,但是在样式上没有做对应的调整,我们必须在wxss中设置布局才可以达到预期效果。最容易想到的就是我们常用的flex布局,关于flex布局的内容比较多,这里就不展开了,推荐看官方文档学习。在进行下一步修改前,先声明几个必须要知道的小细节: 组件scroll-view是不支持flex布局的,要想在scroll-view中使用flex布局,必须嵌套一个其他的支持flex布局的容器,如view。 scroll-view 中的需要滑动的元素不可以用 float 浮动。 scroll-view 中在需要装载滑动元素的父容器中开启flex布局是没有作用的,应该使用dislay:inline-block来进行元素的横向编排。 第一种方法,由于要实现的是横向滑动列表,那么容器中的元素一定是不允许换行的,刚刚提到,scroll-view是不支持flex布局的,所以开启flex布局并设置flex-wrap=nowrap是无效的行为。我们选择在类scroll-x-list中设置white-space: nowrap来处理元素中的空白,让容器内的换行无效。同时,还应设置装载滑动元素的父容器——view-parent的dislay为inline-block,代码如下: [代码]/* index.wxss */ .scroll-x-list{ height:150px; white-space: nowrap; } .view-parent{ display:inline-block; } [代码] 显示效果如下,已经可以横向滚动列表了。 [图片] 第二种方法,可以在scroll-view中嵌套一个view,在这个view中开启flex布局并设置flex-wrap=nowrap来阻止换行,代码如下: [代码]<!-- index.wxml 另一种横向滑动列表 --> <text style="margin-left: 40%;">横向滑动列表</text> <scroll-view scroll-x="true" class="scroll-x-list"> <view class='flex-view'> <view wx:for="{{list}}" wx:key="{{index}}" class="view-parent"> <view class="view-item">{{item.txt}}</view> </view> </view> </scroll-view> /* index.wxss */ .scroll-x-list{ height:150px; } .flex-view{ display:flex; flex-wrap: nowrap; } .view-parent{ display:inline-block; } [代码] 显示效果与刚刚相同: [图片] 一些改进 在第一种方法中,我们没有使用到flex布局,就很容易遇到一些对齐的问题,假设我们设置数组中第三个元素为空,就会出现下面的情况: [图片] 原因很简单,inline-block的属性中在某个元素没有内容的情况下,它的基线对齐方式是基于这个元素的底边的,解决方式是设置一个垂直的对齐方式: [代码]/* index.wxss */ .view-parent{ display:inline-block; vertical-align: top; } [代码] 显示效果如下: [图片] 同时,你会发现第二种开启flex布局方法的横向列表不会有这种对齐的问题,我们还可以在装载滑动元素的容器中开启flex布局来让内容更加美观: [代码].view-item{ width:100px; height:100px; background:#1bf891; margin-right: 20px; align-items:center; display:flex; justify-content:center; } [代码] 显示效果如下: [图片] 总结 scroll-view是一个十分常见实用的组件,但是使用时也有一些需要注意的问题,比如不支持直接使用flex布局。总体来看,比起设置inline-block的布局,更推荐在scroll-view中嵌套一层view再开启flex布局的方法,可以更灵活的摆放控制滑动元素。
2021-11-15 - 用户登录后如何让小程序各个页面保持同步的“登录”状态?
如题,目前有从其他网站上借鉴的登录的方法。我希望用户从底部栏“首页”点击“登录”后,在底部栏“我的”那页上也可以保持“登录”的状态。 目前的问题是,从“首页”登录后,只能展现首页的页面,“我的”那页上还是等待登录的页面。 不知道有什么办法可以实现不同页面上的数据共通呢? [图片]
2023-02-25 - 【笔记】WXSS中定位属性position的使用总结
前言 WXSS (WeiXin Style Sheets)是微信开发的样式语言,用于描述 WXML 的组件样式,它具有CSS 的大部分特性。关于在定位时常用到的属性position,文档中没有对应的描述,所以我自己总结了position的一些基础知识点。 定位 定位的目的是为了更好控制和摆放box,从而实现需要的网页布局。与flex布局的容器、坐标轴等概念不同,定位布局可以轻松任意指定box的摆放位置,定位的属性分为两种,一是边的偏移,二是定位的方式。 边偏移 边偏移有四个属性,分别是top,left,right和bottom,对应于基于顶部,左边,右边和底部的偏移。注意,如果position是默认值,也就是静态定位static时,指定边偏移是无效的行为。例如下面的代码,对于static-view类选择器,我们没有指定position的值,因此position设为默认值static,此时指定属性left是无效的行为: [代码]/* index.wxss */ .static-view{ height: 100px; width: 100px; background-color:red; left:50px; /* position: static; */ } [代码] 显示效果如下,红色正方形仍然贴着屏幕左端: [图片] 定位方式 定位的方式即position的值,常用的有五种,分别是静态定位static(默认值), 相对定位relative, 绝对定位absolute, 固定定位fixed和粘性定位sticky。接下来分别介绍一下各种定位方式的区别。 静态定位 static 静态定位是所有元素的默认定位方式,当你没有为元素指定position的值时,默认值就是static,举个例子,在.wxml中渲染三个不同颜色的view,它们的position都为默认的static: [代码]<!-- index.wxml --> <view class='view-red'></view> <view class='view-blue'></view> <view class='view-green'></view> /* index.wxss */ .view-red{ height: 100px; width: 100px; background-color:red; /* position: static; */ } [代码] 显示效果如下,三个view按照标准流的方式排列: [图片] 注意,在静态定位状态下,无法通过边偏移属性(top、bottom、left或right)来改变元素的位置。 相对定位 relative 相对定位是将元素相对于它的正常位置进行定位的,所谓的正常位置就是position为static时元素在标准文档流中的位置。相对定位的position值为relative,我们修改刚刚红色正方形的position为relative,并设置left为50px: [代码]/* index.wxss */ .view-red{ height: 100px; width: 100px; background-color:red; left: 50px; position: relative; } [代码] 显示效果如下,可以看到红色正方形相对于刚刚的位置向右偏移了50px: [图片] 绝对定位 absolute 绝对定位比较特殊,因为它脱离了标准文档流,以其父容器或父容器中最近的非static(其他四种定位方式)元素的位置为参考。如果没有找到这样的非static元素,就以page作为参考。绝对定位的position值为absolute,我们修改蓝色正方形的position为absolute,并设置left为100px,top为100px;: [代码]/* index.wxss */ .view-blue{ height: 100px; width: 100px; background-color:blue; left:100px; top:100px; position: absolute; } [代码] 显示效果如下,由于没有非static的父容器,view-blue以page为参考位置,left和top指定了它的偏移。还可以看到,绿色正方形在原来的位置向上移动了,原因是蓝色正方形使用了绝对定位,脱离了标准文档流,就为绿色正方形“腾出”了它原来的位置。 [图片] 我们换个例子,让红色正方形作为蓝色正方形的父容器,代码如下: [代码]<!-- index.wxml --> <view class='view-red'> <view class='view-blue'></view> </view> /* index.wxss */ .view-red{ height: 300px; width: 300px; background-color:red; left: 50px; position: relative; } .view-blue{ height: 100px; width: 100px; background-color:blue; left:200px; top:100px; position: absolute; } [代码] 显示效果如下,可以看出此时蓝色正方形以红色正方形的位置作为参考: [图片] 固定定位 fixed 固定定位也脱离了标准文档流,可以把它理解为以page为参考的绝对定位,固定定位的position值为fixed,我们常常会在顶部或底部导航栏中使用固定定位。以自定义tabBar组件为例: [代码].tab-bar { position: fixed; bottom: 0; left: 0; right: 0; height: 48px; background: white; display: flex; padding-bottom: env(safe-area-inset-bottom); } [代码] 显示效果如下,无论如何滚动,tabBar都会固定在屏幕底部。 [图片] 关于自定义tabbar组件,可以查看该代码片段:自定义tabBar组件 粘性定位 sticky 粘性定位的元素依赖于用户的滚动,在相对定位和固定定位之间切换。一般情况下,sticky等同于relative,当页面滚动超出目标区域时,它便切换为fixed,固定在目标位置。目标位置通过指定top, left, right和bottom来设置。修改代码如下: [代码]<!-- index.wxml --> <view style="height:100px"></view> <view class='view-blue'></view> <view class='view-green'></view> <view style="height: 3000px;"></view> /* index.wxss */ .view-blue{ height: 100px; width: 100px; background-color:blue; position: relative; } .view-green{ height: 100px; width: 100px; background-color:green; position: sticky; top:0px; } [代码] 显示如下,此时绿色正方形是相对定位,在标准文档流中: [图片] 下拉滚动条100px,可以看出绿色正方形仍为相对定位: [图片] 继续下拉滚动条,可以发现蓝色正方形消失,但绿色正方形一直处于屏幕顶端,此时已经切换为固定定位: [图片] 覆盖问题 在开发中,我们常常使用子元素绝对定位,父元素相对定位的方法来控制布局,但是仍会遇到不同元素的覆盖现象,可以通过设置属性z-index来解决。z-index的默认值是0,取值越大,定位元素在层叠次序中就越优先;如果取值相同,则以后渲染的优先。 总结 定位布局是各自布局方法中较为简单的一种,它的属性一是边偏移,二是定位方式,两者配合使用才可以构造出美观的布局。
2021-11-10 - 小程序功能全部为登录后才可以使用的功能,手机号授权登录必须授权才能登录这样不行么?
我们的小程序主要功能是To B企业用户,出于数据安全和保密考虑,只开放给已授权的用户登录使用,并提供了两种登录方式:手机号授权登录和账号密码登录。完成登录后能进入小程序进行一系列操作,不登录不能使用。目前登录首页有“仅供已授权品牌用户使用”的字样及两种登录按钮展示。 给不同企业人员开通账号是根据手机号码开通的,这个也是在开通账号时已告知过用户的。 目前手机号授权登录已被封禁,这种要怎么整改? 反馈给客服,客服说要在未获取到授权手机号时,针对非特定用户禁止他点击手机授权去获取手机号,可以不获取手机号我怎么只要他是不是特定用户呢?求解答
01-02