微信小程序入门与实战笔记

微信小程序

目录

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 是用来编写页面骨架的文件

组件类似于

容器 分割文档,没有什么实际意义

文本组件,切记一些比较特别的标记,比如/n加在里面会显示文字换行

图片组件

示例:

<!--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 定位,作用是确定元素的位置

定位永远没有绝对的位置,都有参考系

定位分以下类型:

  1. - 绝对定位 absolute
  2. - 相对定位 relative
  3. - 固定在页面的定位 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-dotsbooleanfalse是否显示面板指示点1.0.0
indicator-colorcolorrgba(0, 0, 0, .3)指示点颜色1.1.0
indicator-active-colorcolor#000000当前选中的指示点颜色1.1.0
autoplaybooleanfalse是否自动切换1.0.0
currentnumber0当前所在滑块的 index1.0.0
intervalnumber5000自动切换时间间隔1.0.0
durationnumber500滑动动画时长1.0.0
circularbooleanfalse是否采用衔接滑动1.0.0
verticalbooleanfalse滑动方向是否为纵向1.0.0
previous-marginstring“0px”前边距,可用于露出前一项的一小部分,接受 px 和 rpx 值1.9.0
next-marginstring“0px”后边距,可用于露出后一项的一小部分,接受 px 和 rpx 值1.9.0
display-multiple-itemsnumber1同时显示的滑块数量1.9.0
skip-hidden-item-layoutbooleanfalse是否跳过未显示的滑块布局,设为 true 可优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息1.9.0
easing-functionstring“default”指定 swiper 切换缓动动画类型2.6.5
bindchangeeventhandlecurrent 改变时会触发 change 事件,event.detail = {current, source}1.0.0
bindtransitioneventhandleswiper-item 的位置发生改变时会触发 transition 事件,event.detail = {dx: dx, dy: dy}2.4.3
bindanimationfinisheventhandle动画结束时会触发 animationfinish 事件,event.detail 同上1.9.0

4.3全局配置和页面配置

全局配置

每一个小程序页面也可以使用同名 .json 文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.jsonwindow 中相同的配置项。

完整配置项说明请参考小程序页面配置

例如:

{
  "navigationBarBackgroundColor": "#ffffff",
  "navigationBarTextStyle": "black",
  "navigationBarTitleText": "微信接口功能演示",
  "backgroundColor": "#eeeeee",
  "backgroundTextStyle": "light"
}

页面配置

每一个小程序页面也可以使用同名 .json 文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.jsonwindow 中相同的配置项。

完整配置项说明请参考小程序页面配置

例如:

{
  "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

属性类型默认值必填说明
titlestring提示的标题
contentstring提示的内容
showCancelbooleantrue是否显示取消按钮
cancelTextstring‘取消’取消按钮的文字,最多 4 个字符
cancelColorstring#000000取消按钮的文字颜色,必须是 16 进制格式的颜色字符串
confirmTextstring‘确定’确认按钮的文字,最多 4 个字符
confirmColorstring#576B95确认按钮的文字颜色,必须是 16 进制格式的颜色字符串
successfunction接口调用成功的回调函数
failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)
object.success 回调函数参数
Object res
属性类型说明最低版本
confirmboolean为 true 时,表示用户点击了确定按钮
cancelboolean为 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查询
        });

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值