微信小程序
目录
- 微信小程序
- 1微信小程序介绍
- 2下载安装
- 3基础知识
- 4配置
- 5 Page页面对象模型
- 6.commonjs 模块导入导出
- 7.template模板
- 8跳转
- 9LeanClound
- 10获取小程序唯一标识
- 11 零散知识
1微信小程序介绍
1.1什么是微信小程序
"不需要"下载就可以应用,安装包<1MB,(目前)
用户“用完即走”,
人与服务的连接,应用将无处不在,随时可用
1.2小程序特点
业务逻辑简单
使用频率低
性能要求低
1.3对开发者的影响
短期内将提升市场对JavaScrip程序员的需求量 |
---|
小程序是0基础开发者很好的入门平台 |
小程序不可用使用现在已经存在JavaScript组件 |
开发环境和开发逻辑及其简单,非常适合新手入门 |
1.4分辨率与rpx
用移动端的思维方式,掌握原理上的知识基础原理,而不是记结论
为什么模拟器下ip6的分辨率是375而设计图一般给750?
1.4.1英寸
一般的英寸都是指对角线,1英寸=2.54CM,所以3.5英寸应该是3.5X2.54=8.89CM,对角线是8.89cm了,计算4:3的比例,按照勾3股4弦5的定律计算,3.5寸屏幕:
长:7.1cm
宽:5.33cm
手机屏幕也称显示屏,用于显示图像及色彩。荧幕尺寸依荧幕对角线计算,通常以英寸(inch)作单位,指荧幕对角的长度。
1.4.1分辨率(pt):
逻辑单位,视觉单位,只和屏幕物理尺寸有关系(长度单位和视觉单位)
1.4.2分辨率(px):
物理像素点,不能描述其大小,一个pt包含多少个px,由reader:(@1x,@2x…)求出.
回答:微信小程序给出的是逻辑分辨率,显示的是pt,而设计师给出的是px(2倍关系)
Iphone下2个px才构成一个pt
1.4.3rpx的作用
1.4.4适配机型
以ip6的物理像素750*1334为视觉稿进行设计,而在小程序中使用rpx为单位
ip6下1px = 1rpx=0.5pt
使用rpx,小程序rpx自动根据不同分辨率换算单位,而使用px为单位不会
2下载安装
2.1申请Appid
https://mp.weixin.qq.com/wxamp/home/guide?token=1019387645&lang=zh_CN 微信公众平台
- 登录公众平台
- 点击侧边栏开发管理 -> 开发设置
- 从开发设置中找到 AppId
2.2下载并安装
[https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/getstart.html#
2.3新建小程序
获取 AppId 后:
- 打开微信开发工具
- 选择小程序,点击新建按钮,打开项目新建向导
- 填写项目名称,项目目录,AppId,后端服务选择不适用云开发,语言选择javascript
- 点击新建按钮,创建项目
2.4页面详细介绍
点击 https://blog.csdn.net/guochanof/article/details/80118035
3基础知识
3.1文件类型与目录结构
项目下的文件和文件夹的作用如下:
pages: 存放页面文件的文件夹
index: 页面文件夹
index.js: 页面的js代码
index.json: 页面的配置
index.wxml: html模板文件
index.wxss: 页面的样式文件
utils: 存放工具类的js文件
app.js: 微信小程序的程序入口(程序入口:开始执行代码的地方)
app.json: 小程序内容的配置文件
app.wxss: 小程序的全局样式(.wxss文件是小程序的样式文件)
project.config.json: 小程序项目的配置
sitemap.json: 访问网站的配置
3.2页面元素
pages数组的第一项代表小程序的初始页面
wxml 是用来编写页面骨架的文件
组件类似于
图片组件
示例:
<!--wxml 是用来编写页面骨架的文件-->
<!--<div>容器 分割文档-->
<view>
<image style="width:200rpx;height:200rpx;" src="/images/1.jpg"></image>
<!--style类似于web开发中的style,rpx:为了使图片的高宽随机性变化,视觉效果更好,px则无变化-->
<text>hello rumei</text>
<view>
<text>开启小程序之旅</text>
</view>
</view>
开发最好以iPhone 6 机型开发,它的换算关系方便 :1px =2rpx
3.3 布局定位
3.3.1布局
布局 layout
布局是什么?
对页面的功能区域进行规划与划分,规定页面元素的区域大小和位置
布局的传统技术
- table 布局
\- div + css 布局
\- div 块级元素,盒子模型可控,受控性好
\- css
\- float 浮动
\- position 定位
\- 用在调整个别元素的位置
\- flex 弹性盒布局
3.3.2定位
position 定位,作用是确定元素的位置
定位永远没有绝对的位置,都有参考系
定位分以下类型:
- - 绝对定位 absolute
- - 相对定位 relative
- - 固定在页面的定位 fixed
定位时,修改元素位置,使用 top bottom left right 属性
绝对定位
参考系:页面的视口(viewport:页面的可见区域)
top bottom left right:这四个属性用于描述元素的四边,距离视口的四边的距离
**修改绝对定位的参考系 **
绝对定位参考系可以修改,修改需要绝对定位元素的父元素,在父元素上添加定位属性即可
修改之后的参考系将变为父元素的上下左右边框
相对定位
参考系:使用定位前的初始位置,就是相对定位的参考位置
top bottom left right:这四个属性用于描述元素初始位置到元素移动后的实际位置的距离
固定在页面的定位
参考系:和绝对定位相同,但是无法修改参考系
top bottom left right:这四个属性用于描述元素的四边,距离视口的四边的距离
3.4flex布局
什么时候使用flex布局?
在一个父元素下有多个子元素,同时需要对多个子元素进行排列时就可以使用flex布局
核心概念
- flex布局是css代码布局的一种
- flex布局分为两部分,一部分在父元素上,一部分在子元素上,父元素上的flex布局属性必不可少
- - flex 布局的排列方式,是按照轴进行排列,轴分为主轴,交叉轴
- - 开启flex布局以后,默认情况,主要轴水平向右,交叉轴竖直向下
/flex 布局 弹性盒子模型 /
/* 开启flex布局 */
display: flex; /* 这句话必不可少 */
修改子元素在主轴上的排列方式
justify-content: flex-start;
/* 靠主起始实位置排列 */
justify-content: flex-end;
/* 靠末尾位置排列 */
justify-content: center;
/* 居中 */
justify-content: space-around;
/* 每个子元素主轴上间距相等 */
justify-content: space-evenly;
/* 每个子元素主轴上平均分布 */
justify-content: space-between;
/* 每个子元素主轴上两端分布 */
交叉轴的排列方式 (确定了主轴与之交叉的那个条轴)
align-items: flex-start;/* 靠交叉轴起始位置排列 */
align-items: flex-end;/* 靠末尾位置排列 */
align-items: center; /* 居中 */
align-items: stretch; /*在交叉轴上自动填满高度或宽度 */
修改主要轴方向
flex-direction: row;/* 从左到右 */
flex-direction: row-reverse;/* 从右到左 */
flex-direction: column;/* 从上到下 */
flex-direction: column-reverse;/* 从下到上 */
align-self:center;/*单独修改子元素在交轴上的排列方式(对齐方式)*/
flex-grow:/*可以让子元素长大(长大指的是:主轴上若有剩余空间,则填满剩余空间)值填正整数数
3.5 iconfont矢量图标
iconfont矢量图标
什么是矢量图
计算机用点坐标加上线和面来描述一幅图,这样的图称为矢量图
矢量的特点:
由于矢量图是由坐标描述出来的,图形是由浏览器动态绘制的,所以当图像在放大或缩小的时候,不会失真,且非常清晰不会模糊
下载
下载方法,可以通过适量图库来下载
阿里图库:https://www.iconfont.cn/
选择图标库,加入到自己的项目中,然后在 资源管理 -> 我的项目 中,下载图标库
批量加入购物车的方法
let arr = document.querySelectorAll('.icon-cover>span[title="添加入库"]')
for(let i=0;i<arr.length;i++){
arr[i].click()
}
html 页面的使用方法
- 将下载下来的 css 文件 和 ttf woff woff2 的文件放在项目的同一个目录下
- 创建一个页面index.html,在页面中使用 link 标签引入 iconfont.css 文件
- 创建一个 span 标签,在span标签上添加 class=“iconfont”,查询图标的class名称,并添加图标的class到span标签上即可
感叹号加tab键
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./font/iconfont.css">
</head>
<body>
<span class="iconfont icon-falling"></span>
</body>
</html>
4配置
4.1页面颜色设置
设置背景颜色覆盖整个页面
Page{
background-color: #b3d4db;
height: 100%;
}
设置顶部导航栏颜色
"window":{
"navigationBarBackgroundColor":
"#b3d4db"
}
常见颜色参考: https://www.w3school.com.cn/cssref/css_colornames.asp
4.2Swiper组件
微信开发文档----组件----Swiper组件
<view>
<swiper>
<swiper-item>Content</swiper-item>
<swiper-item>Content</swiper-item>
<swiper-item>Content</swiper-item>
</swiper>
</view>
只能放在组件中,永远充满整个组件
如果要控制一个轮播图的宽度和宽度,把style写在里面
<view>
<swiper style="width:100%;height:500rpx">
<swiper-item>
<image src="/images/wx.png"">
</image>
</swiper-item>
<swiper-item>Content</swiper-item>
<swiper-item>Content</swiper-item>
</swiper>
</view>
所有不能解决的问题都去翻看文档,不懂得就尝试,一个一个的尝试
基础库 1.0.0 开始支持,低版本需做兼容处理。
滑块视图容器。其中只可放置swiper-item组件,否则会导致未定义的行为。
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
indicator-dots | boolean | false | 否 | 是否显示面板指示点 | 1.0.0 |
indicator-color | color | rgba(0, 0, 0, .3) | 否 | 指示点颜色 | 1.1.0 |
indicator-active-color | color | #000000 | 否 | 当前选中的指示点颜色 | 1.1.0 |
autoplay | boolean | false | 否 | 是否自动切换 | 1.0.0 |
current | number | 0 | 否 | 当前所在滑块的 index | 1.0.0 |
interval | number | 5000 | 否 | 自动切换时间间隔 | 1.0.0 |
duration | number | 500 | 否 | 滑动动画时长 | 1.0.0 |
circular | boolean | false | 否 | 是否采用衔接滑动 | 1.0.0 |
vertical | boolean | false | 否 | 滑动方向是否为纵向 | 1.0.0 |
previous-margin | string | “0px” | 否 | 前边距,可用于露出前一项的一小部分,接受 px 和 rpx 值 | 1.9.0 |
next-margin | string | “0px” | 否 | 后边距,可用于露出后一项的一小部分,接受 px 和 rpx 值 | 1.9.0 |
display-multiple-items | number | 1 | 否 | 同时显示的滑块数量 | 1.9.0 |
skip-hidden-item-layout | boolean | false | 否 | 是否跳过未显示的滑块布局,设为 true 可优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息 | 1.9.0 |
easing-function | string | “default” | 否 | 指定 swiper 切换缓动动画类型 | 2.6.5 |
bindchange | eventhandle | 否 | current 改变时会触发 change 事件,event.detail = {current, source} | 1.0.0 | |
bindtransition | eventhandle | 否 | swiper-item 的位置发生改变时会触发 transition 事件,event.detail = {dx: dx, dy: dy} | 2.4.3 | |
bindanimationfinish | eventhandle | 否 | 动画结束时会触发 animationfinish 事件,event.detail 同上 | 1.9.0 |
4.3全局配置和页面配置
全局配置
每一个小程序页面也可以使用同名 .json
文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json
的 window
中相同的配置项。
完整配置项说明请参考小程序页面配置
例如:
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
}
页面配置
每一个小程序页面也可以使用同名 .json
文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json
的 window
中相同的配置项。
完整配置项说明请参考小程序页面配置
例如:
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
}
考虑整体布局水平还是垂直?
察,再写骨架
<view>
<view>
<image></image>
<text></text>
</view>
<text></text>
<image></image>
<text></text>
<view>
<image></image>
<text></text>
<image></image>
<text></text>
</view>
</view>
</view>
4 .4 绝对路径和相对路径
绝对路径:从根目录往上边找
src="/images/post/crab.png"
相对路径:以当前的文件为起点,往上找…/表示上一级
src="../../images/icon/chat.png"
当用绝对路径不行时,试一下相对路径
写css布局时整体着手
一般文字颜色设成 color: #333;,设成#000太黑了,刺眼
常用正文的颜色color:#666;
5 Page页面对象模型
页面生命周期
只有JS具备从服务器的能力
5.1数据绑定
在js代码的函数中读取属性的方法:
Page({
read() {
console.log('read')
// 函数中的 this 代表当前页面对象模型
console.log(this)
// 谁用this.data读取页面属性
console.log(this.data.table)
}
})
给页面属性赋值的方法:
Page({
write() {
// 使用this.setData函数进行赋值,参数是个json对象,需要修改哪个属性,就给该对象添加哪个属性
this.setData({title: '天龙八部'})
}
})
网页获取DOM结点,小程序不支持这样
process:function(){
var date = 'Nov 18 2019'
var date_ele = document.getElementById('id')
date_ele.text = date
}
小程序支持数据绑定
data: {
date:'Nov 18 2019'
},
//只有js里面原来配置的date才有数据绑定,自己定义的不能
数据传输,wxml页面
<text class="post-date">{{date}}</text>
单项数据绑定,双向数据绑定。。。(自动)
目前小程序只能做单项数据绑定
从服务器取回来的数据一般放在onload生命周期里面
onLoad: function (options) {
var post_content1 = {
date:"NOV 18 2019",
title:"正是虾肥蟹壮时",
post_img:"image/post/crab.png",
content:'菊黄蟹正肥,品尝秋之味。徐志摩把“看初花的狄芦”和“到楼外楼吃蟹”,并列为秋天来杭州不能错过的风雅之事;用林妹妹的话讲是“蟹丰嫩玉双双满”',
view_num: '112',
collect_num:'96',
author_img:'/images/avatar.png',
}
console.log('onload')
},
但页面上还是不会出现,因为再date下才满足
this.setData()方法绑定数据
this.setData(post_content1)
//把数据拷贝到date中来
注意:
src="{{author_img}}"//如果绑定数据位于标签属性上面,不能把这个“”去掉
数据绑定扩展用法
<swiper vertical="{{flase}}">
</swiper>
//字符串‘flase’还是会判定为true
两层的java script对象
var post_content1 = {
date:"NOV 18 2019",
title:"正是虾肥蟹壮时",
img:{
post_img: "/images/post/crab.png",
author_img: '/images/avatar.png',
},
}
<image class="post-author" src="{{img.author_img}}"></image>
{{}}会自己运算
{{'hello'+title}}
5.2条件、列表渲染
wx:if条件渲染
控制元素的隐藏
<text wx:if="{{text_condition}}" class="post-date">{{date}}</text>
//是否隐藏完全取决于text_condition的值是false还是true
wx:for列表渲染
<!-- array: 来自js data中的数组 -->
<!-- 使用 wx:for 一定要加上 wx:key,wx:key的值是array对象中的不可重复的属性 -->
<view wx:for="{{array}}" wx:key="id">
<!-- index: 是 wx:for 中隐式声明的变量,代表循环遍历array时的当前索引 -->
<!-- item: 是 wx:for 中隐式声明的变量,代表循环遍历array时的当前数组成员 -->
{{index}}: {{item}}
</view>
<view wx:for="{{table}}" wx:key="name">
<text>{{index}}: 姓名 = {{item.name}}; 年龄 = {{item.age}}; 性别 = </text>
<!-- wx:if 指令的值为布尔表达式,为true是渲染该节点,否则不渲染 -->
<text wx:if="{{item.sex==='male'}}">男</text>
<!-- wx:if 可以和 wx:elif、wx:else 连用 -->
<text wx:elif="{{item.sex==='female'}}">女</text>
<text wx:else>其他</text>
</view>
<block wx:for={{posts_key}}>
<view class="container">
.....
</view>
</block>
#用把要循环的代码包裹起来,posts_content是一个js代码集合
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var posts_content =[{
date:"NOV 18 2019",
title:"正是虾肥蟹壮时",
post_img: "/images/post/crab.png",
author_img: '/images/avatar.png',
content:'菊黄蟹正肥,品尝秋之味。徐志摩把“看初花的狄芦”和“到楼外楼吃蟹”,并列为秋天来杭州不能错过的风雅之事;用林妹妹的话讲是“蟹丰嫩玉双双满”',
view_num: '112',
collect_num:'96',
},{
date: "SEP 23 2020",
title: "比利.林恩的中场故事",
post_img: "/images/post/b1.png",
author_img: '/images/avatar/2.png',
content: '李安是一位绝不会重复自己的导演,本片将极富原创性李安中所瞩目的新片《比利林恩漫长的中场休息》,正式更名为《半场无战事》。',
view_num: '96',
collect_num: '112',
}]
text_condition: true
console.log('onload')
this.setData({posts_key:posts_content})#传的东西一定要是javascript对象
},
序号wx:for-index=“index”
<block wx:for="{{posts_key}}" wx:for-item="item" wx:for-index="index">
<text>{{index}}</text>
<view class="container">
......
</view>
</block>
5.4事件机制----捕捉与回调
事件机制,需要在代码里监听这个事件。
流程 逻辑顺序:
产生事件 捕捉事件 回调函数 处理事件
<view class="moto-container" bind:tap="onTap">
<text class="moto">开启小程序之旅</text>
</view>
/*tap事件,监听一个事件bind:tap,"onTap"自定义回调函数,函数写在js里面*/
Page({
onTap: function () {
//wx.navigateTo({
//url: '../posts/posts'
//})
wx.redirectTo({
url: '../posts/posts'
})
})
//wx:lu'you
catch:tap 阻止小程序向上冒泡
小技巧:按住alt+shift+F可以格式化代码样式
6.commonjs 模块导入导出
模块导入导出语法的名称叫做:CommonJs
微信小程序项目中的js文件称为一个模块
导出:js模块中,想要提供给其他js模块使用的内容,可以使用导出语句进行导出
导入:将其他js模块中导出的内容引入到使用导入语句的js文件中
const local_database = () =>{
console.log("您好錒!")
}
module.exports={
postList: local_database
}
// 给 module.exports 进行赋值,赋值的内容就是导出的内容,可以是任意内容
//module.exports = something
//使用require函数导入模块
var postsData = require('../../data/posts-data.js')
//小程序不支持绝对路径
onLoad: function (options) {
this.setData({posts_key:postsData.postList})
},
循环依赖问题
现象:若存在两个模块m1 m2,m1依赖了m2, m2又依赖了m1,这样的依赖方式就产生了循环依赖(你中有我,我中有你)
破解方法:
-使用js消息
7.template模板
只能对页面和样式骨架,即wxss和wxml里面的代码进行复用,但是不能服用业务逻辑即js里面的代码
新版里面可以创建自定义组件复用,但难度较大
有选择地选择template模板!!!
<template name="postItem">
......
<template>
<import src="post-item/post-item-template.wxml"/>
.......
<block wx:key="key" wx:for="{{posts_key}}" wx:for-item="item" wx:for-index="idx">
<template is="postItem" data="{{item}}"/>
</block>
//postItem是模板的名字
8跳转
onPostTap:function(event){
var postId = event.currentTarget.dataset.postid;
wx.navigateTo({
url: 'post-detail/post-detail',
})
}
event事件对象,dataset所有的自定义属性的的集合(data-…)
<view catchtap="onPostTap" data-postid="{{item.postId}}">
<template is="postItem" data="{{...item}}"/>
</view>
缓存Storage的基本用法
storige里面查看
缓存的上限最大不能超过10MB
wx.setStorageSync('key', "风暴英雄")
如果用户不主动清理缓存,那么缓存一直存在
wx.setStorageSync('key',{
game:"风暴英雄",
developer:"暴雪"
})
//修改缓存
如何获取?
<image catchtap="onCollectiontap" src="/images/icon/collection.png"></image>
//在标签上加事件
onCollectionTap:function(event){
var game = wx.getStorageSync('key')
}
//js中加事件响应函数
清除缓存
onShareTap:function(event){
wx.removeStorageSync('key')//清除单一的缓存
//wx.clearStorageSync();清除全部的缓存
}
使用缓存实现文章收藏
//同步方法,最好选择同步
var postsCollected = wx.getStorageSync('posts_collected')
if (postsCollected) {
var postCollected = postsCollected([postId])
if (postCollected) {
this.setData({
collected: postCollected
})
}
} else {
var postsCollection = {}
postsCollected[postId] = false;
wx.setStorageSync('posts_collected', postsCollected);
}
},
onCollectionTap: function(event) {
var postsCollected = wx.getStorageSync('posts_collected');
var postCollected = postsCollected[this.data.currentPostId];
postCollected = !postCollected; //取反,收藏变成未收藏,未收藏变成收藏
//更新
postCollected[this.data.currentPostId] = postCollected;
//更新文章是否的缓存值
wx.setStorageSync('posts_collected', postCollected);
//更新数据绑定的变量,从而实现切换图片
this.setData({
collected: postCollected
})
}
同步和异步方法对比
//异步:优点主线流程会很快走完,但回调函数较长,代码可读性差,根据业务逻辑选择异步还是同步
get PostCollectedAsy:function(){
var that = this;
wx.getStorage({
key:"post_collected",
success:function(res){
var postcollected = res.data;
var postcollected = postscollected[that.data.currentPostId];
postcollected = !postcollected;
postscollected[that.data.currentPostId] = postcollected;
that.showToast(postcollected, postscollected);
}
})
}
交互反馈wx.showToast
自动消失
wx.showToast({
title:postcollected?'收藏成功':'取消成功',
duration:1000,
icon:"success"
})
操作反馈wx.showModal
##wx.showModal(Object object)
显示模态对话
Object object
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
title | string | 否 | 提示的标题 | |
content | string | 否 | 提示的内容 | |
showCancel | boolean | true | 否 | 是否显示取消按钮 |
cancelText | string | ‘取消’ | 否 | 取消按钮的文字,最多 4 个字符 |
cancelColor | string | #000000 | 否 | 取消按钮的文字颜色,必须是 16 进制格式的颜色字符串 |
confirmText | string | ‘确定’ | 否 | 确认按钮的文字,最多 4 个字符 |
confirmColor | string | #576B95 | 否 | 确认按钮的文字颜色,必须是 16 进制格式的颜色字符串 |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.success 回调函数参数
Object res
属性 | 类型 | 说明 | 最低版本 |
---|---|---|---|
confirm | boolean | 为 true 时,表示用户点击了确定按钮 | |
cancel | boolean | 为 true 时,表示用户点击了取消(用于 Android 系统区分点击蒙层关闭还是点击取消按钮关闭) | 1.1.0 |
9LeanClound
LeanCloud简介
官网: https://www.leancloud.cn/
云服务是什么
云,指的是云端,也就是互联网上的远程端
云服务:远程端提供的服务,就叫云服务。
例如:百度云,阿里云,腾讯云
LeanCloud介绍
LeanCloud就云服务商家中的一家,它简单方便的提供了数据库云服务。
LeanCloud的作用
LeanCloud可以为我们提供远程服务器和数据库,我们在开发小程序时,需要使用数据库,将数据存储下来,所以我们要用到LeanCloud的数据库服务
SDK (software develepment toolkit) 是啥?
sdk是云服务平台提供的开发工具,用于用户在客户端访问云平台的云服务
下载sdk
地址:https://cdn.jsdelivr.net/npm/leancloud-storage@4.10.1/dist/av-min.js
开发流程:
创建应用
在LeanCloud登录后台,点击创建应用按钮创建一个应用
创建好后,点击应用的存储按钮,进入控制台后,点击侧边栏中的 设置->应用keys 找到和自己应用相关的参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c9TwT3bq-1624935169034)(QQ%E6%88%AA%E5%9B%BE20210616095014.png)]
安装sdk
下载对应小程序的sdk https://leancloud.cn/docs/sdk_setup-js.html#hash1620893804 下载两个文件 core 和 adapter
将下载好的文件放到小程序的 libs 文件夹中
将其中的 index.js 更名为 leancloud-adapters-weapp.js
在 app.js 代码中,引入下载的两个文件
安装适配器
```app.js
// 引入 leancloud sdk
const AV = require('./libs/av-core-min.js')
const adapters = require('./libs/leancloud-adapters-weapp.js')
// 安装适配器
AV.setAdapters(adapters)
\```
初始化sdk
详见:《安装LeanCloundSDK.html》
调用 AV.init 函数进行初始化
```js
AV.init({
appId: “你的 appId”,
appKey: “你的 appkey”,
// server服务器地址,来自于 设置->应用keys 中的"REST API 服务器地址"
serverURL: “https://94ddp1df.lc-cn-n1-shared.com”
})
```
验证sdk是否初始化成功
若console控制台上打印除了 “保存成功。” 则说明sdk已就绪
db.js
// 引入 leancloud sdk
const AV = require('../libs/av-core-min.js');
const adapters = require('../libs/leancloud-adapters-weapp.js');
// 安装适配器
AV.setAdapters(adapters)
// 初始化sdk
AV.init({
appId: "OrbS1lKKCttKAQWDujsb0bHl-gzGzoHsz",
appKey: "nxWvxNWiLYuqB7m1AmqQxv2J",
serverURL: "https://6fky7gxj.lc-cn-n1-shared.com"
})
//验证sdk是否安装成功
const TestObject = AV.Object.extend('TestObject');
const testObject = new TestObject();
testObject.set('words', 'Hello world!');
testObject.save().then((testObject) => {
console.log('保存成功。')
})
module.exports = AV
增删改查crud
const AV = require('../../utils/db.js')
// pages/crud/crud.js
Page({
/**
* 页面的初始数据
*/
data: {
id: undefined,
form: {
no: 'abc',
name: '张三',
sex: 'female',
grade: '3年级',
class: '1班'
},
grade: {
index: 2,
data: [
'1年级',
'2年级',
'3年级'
]
},
class: {
index: 1,
data: [
'1班',
'2班',
'3班'
]
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// 为了回显数据,需要获取学生id,用于数据库查询
let id = options.id
if (id) {
wx.setNavigationBarTitle({ title: '修改学生' })
// 查询数据库,获取对应id的数据
let query = new AV.Query('Student')
query.equalTo('objectId', id)
wx.showLoading({
title: '加载中...',
})
query.find().then((r) => {
console.log(r)
let stu = r[0]
// 回显数据
for (let key in this.data.form) {
this.data.form[key] = stu.attributes[key]
}
this.data.grade.index = this.data.form.grade === '1年级' ?
0 :
this.data.form.grade === '2年级' ?
1 : 2
this.data.class.index = this.data.form.class === '1班' ?
0 :
this.data.form.class === '2班' ?
1 : 2
this.setData({
form: this.data.form,
id: stu.id,
grade: this.data.grade,
class: this.data.class
})
}).catch(reason => {
console.error(reason)
}).finally(() => {
wx.hideLoading()
})
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
// 保存数据
save() {
console.log(this.data.form)
// 通过判断id是否存在,来构造一个学生表的数据对象
let stu = this.data.id ? AV.Object.createWithoutData('Student', this.data.id) : (() => {
// 创建一个用于保存的文档类型(这里的文档相当于sql数据库中的表)
const Student = AV.Object.extend('Student')
// 实例化Student
return new Student()
})()
// if(this.data.id){
// stu = AV.Object.createWithoutData('Student', this.data.id)
// } else {
// // 创建一个用于保存的文档类型(这里的文档相当于sql数据库中的表)
// const Student = AV.Object.extend('Student')
// // 实例化Student
// stu = new Student()
// }
// 需要修改哪个字段的数据,就设置哪个字段的值
let form = this.data.form
for (let key in form) {
stu.set(key, form[key])
}
// 保存
let promise = stu.save()
promise.then((result) => {
console.log(result) // result 中存的是保存成功后的结果
console.log('保存成功')
}).catch((reason) => {
console.error(reason) // reason 是保存失败的理由
console.log('保存失败')
}).finally(() => {
console.log('网络通信结束') // 网络通信结束后一定会执行finally中的回调函数
// 关闭 loading
wx.hideLoading()
wx.navigateBack({
delta: 1,
})
})
},
删除数据
remove() {
if (!this.data.id) return
let stu = AV.Object.createWithoutData('Student', this.data.id)
// 打开删除的询问
wx.showModal({
title: '警告',
content: '确定要删除数据么?',
success(res) {
if (res.confirm) {
console.log('用户点击确定')
wx.showLoading({
title: '删除中',
})
// 调用distroy进行删除
let promise = stu.destroy()
promise.then((r) => {
// 删除成功时执行的代码
console.log(r)
console.log('删除成功')
}).catch(reason => {
// 删除失败时执行的代码
console.error(reason)
}).finally(() => {
wx.hideLoading()
wx.navigateBack()
})
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
},
// 学号输入事件
onNoInput(ev) {
console.log(ev)
this.data.form.no = ev.detail.value // 获取用户输入并修改no的值
this.setData({ form: this.data.form })
},
// 姓名输入事件
onNameInput(ev) {
this.data.form.name = ev.detail.value
this.setData({ form: this.data.form })
},
// 性别选择变化事件
onSexChange(ev) {
console.log(ev)
this.data.form.sex = ev.detail.value
this.setData({ form: this.data.form })
},
// 年级变化事件
onGradeChange(ev) {
console.log(ev)
// 获取索引
let index = ev.detail.value
// 修改当前选择的索引
this.data.grade.index = index
// 修改表单数据中的年级值
this.data.form.grade = this.data.grade.data[index]
this.setData({
grade: this.data.grade,
form: this.data.form
})
},
// 年级变化事件
onClassChange(ev) {
console.log(ev)
// 获取索引
let index = ev.detail.value
// 修改当前选择的索引
this.data.class.index = index
// 修改表单数据中的年级值
this.data.form.class = this.data.class.data[index]
this.setData({
class: this.data.class,
form: this.data.form
})
}
})
// 列表查询
query() {
// 实例化 查询对象
// 参数是表名称
let query = new AV.Query('Student')
// 以 updatedAt 进行降序排列
query.descending('updatedAt')
// 限制查询数量
query.limit(this.data.querySize)
if (this.data.lastTime) {
// 若存储时间戳 则查询比此时间戳更小的时间
// lessThan 函数 查询比指定值更小的数据
query.lessThan('updatedAt', this.data.lastTime)
}
// 加载提示
wx.showLoading({
title: '加载中',
})
// 调用find函数获取promise 对象
let promise = query.find()
promise.then(r => {
console.log(r)
console.log('查询成功')
// 解析数据库参数
let mapResult = r.map((el, index, arr) => {
// 克隆数据库中每条数据的attributes对象
let result = Object.assign({}, el.attributes)
result.id = el.id
result.createdAt = el.createdAt
result.updatedAt = el.updatedAt
return result
})
console.log(mapResult)
this.data.list = [...this.data.list, ...mapResult]
this.setData({
list: this.data.list,
// 保存最新的时间戳
lastTime: this.data.list[this.data.list.length - 1].updatedAt
})
}).catch(reason => {
console.error(reason)
console.error('查询失败')
}).finally(() => {
// 隐藏加载提示
wx.hideLoading()
})
}
showModal: function(postcollected, postscollected) {
var that = this;
wx.showModal({
title: '收藏',
content: postcollected ? '收藏该文章?' : '取消收藏该文章',
showCancel: 'true',
cancelColor: '#333',
cancelText:'取消',
confirmText: '收藏',
confirmColor: '#405f80',
success: function(res) {
if (res.confirm) {
wx.setStorageSync('posts_collected', postscollected)
that.setData({
collected: postcollected
})
}
}
})
},
10获取小程序唯一标识
const express = require('express')
const axios = require('axios')
const qs = require('querystring')
const app = express()
const port = 1024
// 使用官方的https接口,将登录时的 code 转换为 session_key 和 openid
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
const appid = 'wx9b2......'
const secret = 'd6dd01bd.....'
const grant_type = 'authorization_code'
app.use(express.urlencoded({ extended: false }))
app.get('/getUserInfo', (req, res) => {
let params = {
appid,
secret,
grant_type,
js_code: req.query.code
}
console.log(params)
console.log(qs.stringify(params))
axios.get(`https://api.weixin.qq.com/sns/jscode2session?${qs.stringify(params)}`).then(_res => {
console.log(_res)
res.json({ result: _res.data })
}).catch(reason => {
console.log(reason)
res.json({ msg: reason })
})
})
app.listen(port, () => {
console.log('server start on : http://127.0.0.1:' + port)
})
const AV = require('./utils/db.js')
// app.js
App({
// 当启动时触发函数
onLaunch() {
// 展示本地存储能力
const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
wx.request({
url: 'http://127.0.0.1:1024/getUserInfo',
data: res,
success(res) {
console.log(res)
}
})
}
})
},
globalData: {
userInfo: null
}
})
11 零散知识
wx.showActionSheet(Object object)
显示操作菜单
onShareTap:function(event){
var itemlist = [
"分享给微信好友",
"分享到朋友圈",
"分享到QQ",
"分享到微博",
];
wx.showActionSheet({
itemList: itemlist,
itemColor:"#405f80",
success:function(res){
//res.cancel用户是不是点击了取消按钮
//res.tapIndex数组元素的序号,从0开始
wx.showModal({
title: '用户'+itemlist[res.tapIndex],
content: '用户是否取消?'+res.cancel+"现在无法实现分享功能,什么时候能支持呐?",
})
}
})
}
playBackgroundAudio-音乐播放器的基本实现
有一个总控开
OnmusicTap:function(event){
var currentPostId = this.data.currentPostId;
var isplayingmusic = this.data.isplayingmusic;
var postData = postsData.postList[currentPostId];
if (isplayingmusic){
wx.pauseBackgroundAudio();
this.setData({
isplayingmusic:false
})
}
else{
wx.playBackgroundAudio({
dataUrl:postData.music.url,
title: postData.music.title,
coverImgUrl: postData.music.coverImgUrl,
})
this.setData({
isplayingmusic:true
})
}
}
切换图片
<image catchtap="OnmusicTap" class="audio" src="{{isPlayingMusic?'/images/music/music-stop.png':'/images/music/music-start.png'}}"></image>
监听播放事件完善音乐播放
总控开关和业务逻辑之间的桥梁
由框架调用主代码,通过监听函数事件驱动
wx.onBackgroundAudioPlay(function(){
that.setData({
isplayingmusic:true
})
});
wx.onBackgroundAudioPause(function () {
that.setData({
isplayingmusic: false
})
});
应用程序生命周期
app.js里面设置
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
},
/**
* 当小程序启动,或从后台进入前台显示,会触发 onShow
*/
onShow: function (options) {
},
/**
* 当小程序从前台进入后台,会触发 onHide
*/
onHide: function () {
},
/**
* 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
*/
onError: function (msg) {
}
})
var app = getApp();//接收
关于debug
Sourses里面打断点,在sm后缀文件中打断点,按住ctrl + p可以快速搜索
音乐播放状态
App({
globalData:{
g_isplayingmusic:false,//变量表示音乐是不是在播放
g_currentMusicPostId:null//哪一个音乐在播放
}
})//设置全局变量
页面js中引进
var app = getApp();
使用
if (app.globalData.g_isplayingmusic && app.globalData.g_currentMusicPostId===postId){
this.setData({
isplayingmusic:true
})
}
setAudioMonitor: function() {
var that = this;
wx.onBackgroundAudioPlay(function() {
that.setData({
isplayingmusic: true
})
app.globalData.g_isplayingmusic = true;
app.globalData.g_currentMusicPostId = that.data.currentPostId;
});
......
app.globalData.g_isplayingmusic = false;
app.globalData.g_currentMusicPostId = null
}
target与currentTarget区别
//target 和currentTarget
//target指的是当前点击的组件,currentTarget指的是事件捕获的组件
//target这里指的是image,而currentTarget指的是swiper
onSwiperTap:function(event){
var postId = event.target.dataset.postid;
wx.navigateTo({
url: 'post-detail/post-setail?id='+postId
})
}
如果配置了tap栏则需要用第三种路由API跳转方法
onTap: function () {
//wx.navigateTo({
//url: '../posts/posts'
//})
// wx.redirectTo({
// url: '../posts/posts'
// })
//路由API
wx.switchTab({
url: '../posts/posts'
})
}
想让页面出现tabBar,必须要把页面路径放到list下面,成为一个主元素
"tabBar": {
"borderStyle": "white",//设置上边框白色
"list": [
{
"pagePath": "pages/posts/posts",
"text": "阅读",
"iconPath": "/images/tab/yuedu.png",//设置未选中时的图片
"selectedIconPath":"/images/tab/yuedu_hl.png"//设置选中时的图片
},
{
"pagePath": "pages/movies/movies",
"text": "电影",
"iconPath": "/images/tab/dianying.png",
"selectedIconPath":"/images/tab/dianying_hl.png"
}
]
},
RESTful API简介及调用豆瓣API
轻量,可以从网上开放的API调用数据
接口·的url路径可以自描述,看到接口就可以知道他可以获取哪些信息
粒度大?url语义是否清晰易懂?
data: {
inTheaters: {},
comingSoon: {},
top250: {},
searchResult: {},
containerShow: true,
searchPanelShow: false,
},
onReachBottom: function (e) {
console.log('asdfasdfd')
},
onLoad: function (event) {
var inTheatersUrl = app.globalData.doubanBase +
"/v2/movie/in_theaters" + "?start=0&count=3";
var comingSoonUrl = app.globalData.doubanBase +
"/v2/movie/coming_soon" + "?start=0&count=3";
var top250Url = app.globalData.doubanBase +
"/v2/movie/top250" + "?start=0&count=3";
this.getMovieListData(inTheatersUrl, "inTheaters", "正在热映");
this.getMovieListData(comingSoonUrl, "comingSoon", "即将上映");
this.getMovieListData(top250Url, "top250", "豆瓣Top250");
},
getMovieListData: function(url, settedKey, categoryTitle) {
var that = this;
wx.request({
url: url,
method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
header: {
"Content-Type": "json"
},
success: function(res) {
that.processDoubanData(res.data, settedKey, categoryTitle)
},
fail: function(error) {
// fail
console.log(error)
}
})
},
常用灰色字体:#666,或者#333
页面间的(跳转)参数传递方式id
- 利用全局变量
- 利用缓存
- 利用url
- 发生事件、接收事件
API动态设置导航栏标题
onReady及其以后周期设置:
onReady:function(event){
wx.setNavigationBarTitle({
title:this.data.navigateTitle,
})
}
下拉刷新,下滑加载更多
<view class="grid-container">
<block wx:for="{{movies}}" wx:for-item="movie">
<view class="single-view-container">
<template is="movieTemplate" data="{{...movie}}" />
</view>
</block>
</view>
//如果要绑定新加载的数据,那么需要同旧有的数据合并在一起
if (!this.data.isEmpty) {
totalMovies = this.data.movies.concat(movies);
}
else {
totalMovies = movies;
this.data.isEmpty = false;
}
this.setData({
movies: totalMovies
});
onScrollLower:function(event){
var nextURL = this.data.requestURL +
"?start=" + this.data.totalCount + "&count=20"
}
设置等待(loading)的操作
//开启
wx.showNavigigationBarLoading()
//显示转圈等待在导航栏上
//关闭
wx.hideNavigigationBarLoading()
实现下拉刷新操作
开启是一个状态,是在json文件里面
{
"enablePulldownRefresh":"ture"
}
app.json能配置多个,
页面json只能配置windows下的
//再重新加载数据
onPullDownRefresh:function(event){
var refreshUrl = this.data.requestUrl +
"?start=08counth=20";
this.data.isEnpty = true;//把所有状态置空
util.http(refreshUrl,this.processDoubanData);//走HTTP请求
wx.showNavigigationBarLoading()//显示等待状态
}
: function(url, settedKey, categoryTitle) {
var that = this;
wx.request({
url: url,
method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
header: {
"Content-Type": "json"
},
success: function(res) {
that.processDoubanData(res.data, settedKey, categoryTitle)
},
fail: function(error) {
// fail
console.log(error)
}
})
},
常用灰色字体:#666,或者#333
页面间的(跳转)参数传递方式id
- 利用全局变量
- 利用缓存
- 利用url
- 发生事件、接收事件
API动态设置导航栏标题
onReady及其以后周期设置:
onReady:function(event){
wx.setNavigationBarTitle({
title:this.data.navigateTitle,
})
}
下拉刷新,下滑加载更多
<view class="grid-container">
<block wx:for="{{movies}}" wx:for-item="movie">
<view class="single-view-container">
<template is="movieTemplate" data="{{...movie}}" />
</view>
</block>
</view>
//如果要绑定新加载的数据,那么需要同旧有的数据合并在一起
if (!this.data.isEmpty) {
totalMovies = this.data.movies.concat(movies);
}
else {
totalMovies = movies;
this.data.isEmpty = false;
}
this.setData({
movies: totalMovies
});
onScrollLower:function(event){
var nextURL = this.data.requestURL +
"?start=" + this.data.totalCount + "&count=20"
}
设置等待(loading)的操作
//开启
wx.showNavigigationBarLoading()
//显示转圈等待在导航栏上
//关闭
wx.hideNavigigationBarLoading()
实现下拉刷新操作
开启是一个状态,是在json文件里面
{
"enablePulldownRefresh":"ture"
}
app.json能配置多个,
页面json只能配置windows下的
//再重新加载数据
onPullDownRefresh:function(event){
var refreshUrl = this.data.requestUrl +
"?start=08counth=20";
this.data.isEnpty = true;//把所有状态置空
util.http(refreshUrl,this.processDoubanData);//走HTTP请求
wx.showNavigigationBarLoading()//显示等待状态
}
codecademy可以学习
快捷键:选中ctrl+D同时修改
按住alt键不放,点上下键
alt +shift +上箭头,向上复制
判断路径对不对,鼠标悬停,按一下,如何能跳转就正确,alt+左右箭头就会导航返回
json处理
console.log(res.data);
var obj = JSON.parse(res.data)
console.log(obj)
var arry = obj.result.records
var mealDetailList = obj.filter((id)=>{
return p.shiftname=="i"//按id查询
});