原生开发 之 微信小程序

news2024/11/28 20:43:07

目录

一、前期预备

1. 预备知识

​2. 注册账号 - 申请AppID

3. 下载小程序开发工具

4. 小程序项目结构

​5. 小程序的MVVM架构

二、创建小程序项目

1. 查看注册的appId

​2. 创建项目

​3. 新建页面

01 - 创建text页面文件夹

​02 - 新建text的page

​03 - 在app.json中配置

​4. 开发初体验

01 - text.wxml

02 - text.js

03 - 效果

三、小程序的架构和配置

1. 小程序的架构模型

01 - 宿主环境

02 - 双线程模型

​2. 小程序的配置文件

01 - project.config.json

02 - sitemap.json

03 - app.json

        代码

        效果

​04 - (page).json

        代码

        效果

​四、注册小程序 – App函数 - app.js

​作用一 : 判断打开场景

01 - 常见场景

02 - 确定场景

        代码

        效果

​作用二 : 定义全局App的数据

app.js

page.js

效果

​作用三 : 生命周期函数 

五、注册页面 – Page函数 - (page).js

0. 生命周期

1. 发送网络请求

2. 初始数据

3. 绑定事件函数

wxml

js

4. 其他的监听

01 - 下拉刷新

        logs.json

        logs.js

        效果

​02 - 上拉加载更多

        logs.json

        logs.js

        logs.wxml

        效果

​03 - 页面滚动

六、常见的内置组件

Text : 文本组件

Button : 按钮组件

基本用法

open-type属性

        获取用户信息

                wxml

                js

        获取用户手机

                wxml

                js

View : 视图组件

ScrollView滚动组件

上下滚动

        wxml

        css

        js

左右滚动

        wxml

        css

        js 

Image : 图片组件

基本使用 

使用手机本地图片 wx.chooseMedia

        wxml

        js 

Input : 组件

wxml

js

组件的共同属性

七、小程序基础语法

1. Wxss

01 - 样式写法

02 - 选择器

03 - 尺寸单位

2. Wxml

01 - 逻辑判断

02 - hidden

03 - block

04 - 列表渲染

        wx:for

        item - index

        key

3. Wxs

01 - 概念

02 - 写法

        写法一 : 直接写在标签内

        写法二 : 独立的文件,通过src引入

                定义format.wxs

                wxml

八、小程序的事件处理

1. 组件事件类型

2. 事件对象event

01 - currentTarget && target

        wxml

        wxss

        js

02 - touches && changedTouches

        区别一 : touchend中不同

        区别二 : 多手指触摸时不同

03 - 事件参数的传递

        wxml

        js

04 - 事件参数的传递的例子

        wxml

        wxss

        js

        效果

3. 事件冒泡 && 事件捕获

4. 获取元素的宽高等

九、小程序的组件化开发

1. 概念

2. 创建并使用组件

01 - 创建

02 - 配置

03 - 引入组件

        局部注册组件

        全局注册组件

04 - 使用组件

05 - 注意事项

3. 组件的样式细节

01 - 组件内的样式 对 外部样式 的影响

02 - 外部的样式 对 组件内样式 的影响

03 - 如何让class可以相互影响

4. 组件的通信

01 - 向组件传递数据 - properties

        页面定义

        组件接收

02 - 向组件传递样式 - externalClasses

        页面定义

        页面传递

        组件接收

        组件使用

03 - 组件向外传递事件

        组件定义

        组件传递

        页面监听

        页面处理

 04 - 页面直接调用组件方法

        组件定义

        页面定义

        页面使用

5. 组件的插槽

01 - 单个插槽

        组件

        页面

        效果

02 - 具名插槽

        组件定义

        组件配置

        页面使用

03 - 解决默认值问题

        组件

        样式

6. 组件中的混入 - behaviors

01 - 共享的代码

02 - 组件中使用

7. 组件的生命周期

01 - 概念

02 - 组件所在页面的生命周期

8. 组件Component构造器总结图

十、小程序系统API调用

1. 网络请求

01 - API参数

02 - API使用

03 - API封装

        封装成函数

                封装

                使用

        封装成类

                封装

                使用

04 - 网络请求域名配置

2. 展示弹窗效果

01 - showToast

        效果

        代码

02 - showLoading

        效果

        代码

03 - showModal

        效果

        代码

04 - showActionSheet

        效果

        代码

3. 分享功能 onShareAppMessage

方式一

方式二

4. 获取设备信息 wx.getSystemInfo

5. 获取位置信息 wx.getLocation

01 - 授权

02 - 获取

6. Storage存储

01 - 同步

02 - 异步

十一、页面跳转

1. 通过wx的API跳转

00 - switchTab - 跳转到 tabBar 页面

01 - navigateTo - 普通页面跳转

02 - navigateBack - 页面返回

03 - 页面跳转 - 数据传递(一)

        首页 => 详情页

        详情页 => 首页

04 - 页面跳转 - 数据传递(二)

        首页 => 详情页

        详情页 => 首页

2. 通过navigator组件

01 - 跳转到 tabBar 页面

02 - 跳转到 普通 页面

03 - 返回 上一个 页面

十二、小程序登录解析

1. 概念

01 - openid

02 - unionid

03 - 用户身份多平台共享 

2. 登录流程

3. 代码

十三、代码上传到Gitee

1. 创建远程仓库

​2. 配置远程仓库

01 - 本地点击版本管理

​02 - 添加远程仓库

​03 - 设置用户名和邮箱

​04 - 设置网络和认证

​3. 推送代码到远程仓库

01 - 首次推送

​02 - 修改后推送

        推送到本地仓库

        拉取远程仓库代码

​        推送到远程仓库


一、前期预备

1. 预备知识

小程序的核心技术主要是三个:

  • 页面布局:WXML,类似HTML
  • 页面样式:WXSS,几乎就是CSS(某些不支持,某些进行了增强,但是基本是一致的)
  • 页面脚本:JavaScript+WXS(WeixinScript)

2. 注册账号 - 申请AppID

网址 : 微信小程序

3. 下载小程序开发工具

网址 : 微信开发者工具下载地址与更新日志 | 微信开放文档

4. 小程序项目结构

5. 小程序的MVVM架构

Vue的MVVM和小程序MVVM对比

MVVM :  

  • DOM Listeners: ViewModel层可以将DOM的监听绑定到Model层
  • Data Bindings: ViewModel层可以将数据的变量, 响应式的反应到View层
  • MVVM架构将 命令式编程 转移到 声明式编程

二、创建小程序项目

1. 查看注册的appId

网址 : 小程序

2. 创建项目

3. 新建页面

01 - 创建text页面文件夹

02 - 新建text的page

03 - 在app.json中配置

可能会自动注册完成

ps : 也可以反向注册,在这里直接配置,文件夹会自动生成

4. 开发初体验

01 - text.wxml

<!--pages/text/text.wxml-->
<!-- 1. 普通文本 -->
<view>text页面</view>

<!-- 2. 数据绑定,使用 {{}} 这个语法 -->
<view>{{message}}</view>

<!-- 3. 列表渲染 -->
<block wx:for="{{movies}}" wx:key="item">
  <view>item : {{item}} => index: {{index}}</view>
</block>

<!-- 4. 事件监听 -->
<view style="text-align: center">当前计数 : {{counter}}</view>
<button bindtap="increment">+1</button>
<button bindtap="decrement">-1</button>

02 - text.js

直接修改data中的数据,不会引起页面的刷新

小程序和react中都不会,只有vue劫持了属性才能直接操作

 

ps : 修改data并且希望页面重新渲染,必须使用 this.setData()

// pages/text/text.js
Page({
  /**
   * 页面的初始数据
   */
  data: {
    // 1. 数据绑定,{{}} 语法
    message: 'star',
    // 2. 列表渲染数据
    movies: ['迪迦大战肯德基', '图图和小新抢东西吃'],
    // 3. 计数器参数
    counter: 0
  },
  // 监听计数器增加按钮触发
  increment() {
    // 此方法修改后的数据不会在页面上响应
    // this.data.counter += 1
    this.setData({
      counter: this.data.counter + 1
    })
  },
  // 监听计数器减少按钮触发
  decrement() {
    this.setData({
      counter: this.data.counter - 1
    })
  },
})

03 - 效果

三、小程序的架构和配置

1. 小程序的架构模型

01 - 宿主环境

小程序的宿主环境   =>   微信客户端

 

ps :  宿主环境为了执行小程序的各种文件:wxml文件、wxss文件、js文件

02 - 双线程模型

  • 当小程序基于 WebView 环境下时,WebView 的 JS 逻辑、DOM 树创建、CSS 解析、样式计算、Layout、Paint (Composite) 都发生在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿
  • 以此为前提,小程序同时考虑了性能与安全,采用了目前称为「双线程模型」的架构

双线程模型 : 

  • WXML模块和WXSS样式运行于 渲染层,渲染层使用WebView线程渲染(一个程序有多个页面,会使用多个WebView的线程)
  • JS脚本(app.js/home.js等)运行于 逻辑层,逻辑层使用JsCore运行JS脚本
  • 这两个线程都会经由微信客户端(Native)进行中转交互
  • 注 : wxs是和渲染层呆在一起的

2. 小程序的配置文件

01 - project.config.json

项目配置文件   =>   比如项目名称、appid等

 

网址 : 项目配置文件 | 微信开放文档

02 - sitemap.json

小程序搜索相关的

 

网址 : sitemap 配置 | 微信开放文档

03 - app.json

全局配置

 

网址 : 全局配置 | 微信开放文档

  • pages : 页面路径列表
    • 用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息
    • 小程序中所有的页面都是必须在pages中进行注册的
    • 全局配置 - pages | 微信开放文档
  • window : 全局的默认窗口展示
    • 用户指定窗口如何展示, 其中还包含了很多其他的属性
    • 全局配置 - window | 微信开放文档
  • tabBar : 顶部tab栏的展示
    • 全局配置 - tabBar | 微信开放文档

        代码

{
  "pages": [
    // 默认显示的页面
    "pages/text/text",
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window": {
    // 下拉 loading 的样式,仅支持 dark 黑色 / light 白色
    // 需要到页面的.json中加入 "enablePullDownRefresh": true , 开启即可
    // 最好别在全局开启下拉刷新
    "backgroundTextStyle": "dark",
    // 导航栏背景颜色
    "navigationBarBackgroundColor": "#f00",
    // 导航栏标题文字内容
    "navigationBarTitleText": "Weixin",
    // 导航栏标题颜色,仅支持 black / white
    "navigationBarTextStyle": "black"
  },
  // 底部导航按钮
  "tabBar": {
    // 文字默认的颜色
    "color":"#fff",
    // 选中时文字的颜色
    "selectedColor":"#ff8189",
    // 导航是一个数组
    "list": [
      {
        // 页面路径
        "pagePath": "pages/index/index",
        // 文本
        "text": "首页",
        // 默认显示的图标
        "iconPath": "assets/images/tabbar/home.png",
        // 选中时显示的图标
        "selectedIconPath": "assets/images/tabbar/home_active.png"
      },
      {
        "pagePath": "pages/text/text",
        "text": "记录",
        "iconPath": "assets/images/tabbar/category.png",
        "selectedIconPath": "assets/images/tabbar/category_active.png"
      }
    ]
  },
  // 表明启用新版的组件样式
  "style": "v2",
  // 配置搜索相关文件,基本不需更改
  "sitemapLocation": "sitemap.json"
}

        效果

04 - (page).json

页面配置

每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置

页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项

网址 : 页面配置 | 微信开放文档

        代码

{
  // 是否使用组件
  "usingComponents": {
    // 需要在这里配置
  },
  // 页面顶部标题文字
  "navigationBarTitleText": "冲啊",
  // 页面顶部标题颜色
  "navigationBarTextStyle": "white",
  // 页面顶部背景颜色
  "navigationBarBackgroundColor": "#0f0",
  
  // 是否开启下拉刷新 
  // Page.js 中,onPullDownRefresh 开启这个,可以监听到是否下拉刷新了
  "enablePullDownRefresh": true,
}

        效果

四、注册小程序 – App函数 - app.js

每个小程序都需要在 app.js 中调用 App 函数 注册小程序示例

 

网址 : App(Object object) | 微信开放文档

  • 在注册时, 可以绑定对应的生命周期函数
  • 在生命周期函数中, 执行对应的代码

注册App时,一般做如下事情 : 

  • 监听生命周期函数,在生命周期中执行对应的业务逻辑,比如在某个生命周期函数中进行登录操作或者请求网络数据
  • 判断小程序的进入场景
  • 因为App()实例只有一个,并且是全局共享的(单例对象),所以我们可以将一些共享数据放在这里

作用一 : 判断打开场景

01 - 常见场景

小程序的打开场景较多 : 

  • 常见的打开场景
    • 群聊会话中打开
    • 小程序列表中打开
    • 微信扫一扫打开
    • 另一个小程序打开
  • 场景值 : 微信开放文档 - 场景值列表

02 - 确定场景

在 onLaunch 和 onShow 生命周期回调函数中,会有options参数,其中有scene值

        代码

// app.js
App({
  /**
   * 生命周期回调——监听小程序初始化。
   * 小程序初始化时触发,只有执行一次
   */
  onLaunch(options) {
    console.log('onLaunch =>', 'scene :', options.scene);
    // 登录
    wx.login({
      success: res => {
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
      }
    })
  },
  /**
   * 生命周期回调——监听小程序启动或切前台
   * 每次打开小程序都会执行
   */
  onShow(options) {
    console.log('onShow   =>', 'scene :', options.scene);
    // 可根据场景值,跳转到对应的页面
    wx.navigateTo({
      // url: 'url',
    })
  },
  onHide() {
    console.log('onHide   => 隐藏~');
  }
})

        效果

作用二 : 定义全局App的数据

注意 : 定义在全局的数据不会响应式

 

共享的数据通常是一些固定的数据

app.js

// app.js
App({
  // 定义的全局变量
  globalData: {
    token: '',
    userInfo: {
      name: 'coder',
      age: 18
    }
  },
  // 页面初始化调用的回调函数
  onLaunch(options) {
    // 登录
    wx.login({
      success: res => {
        console.log('code =>', res.code);
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
        this.globalData.token = res.token || 'abcdefghijklmnopqrstuvwxyz'
      }
    })
  }
})

page.js

// pages/text/text.js
Page({
  // 页面加载的时候触发
  /**
   * 获取页面所需数据
   */
  onLoad() {
    // 获取共享的数据
    // 1. 获取app实例对象
    const app = getApp()
    // 2. 从app实例对象中获取数据
    const token = app.globalData.token
    const userInfo = app.globalData.userInfo
    console.log('userInfo :', userInfo);
    console.log('token :', token);
    // 3. 拿到token后发送网络请求
    // wx.request({
    //   url: 'url',
    //   token
    // })
    // 4. 展示数据到页面
    this.setData({
      userInfo
    })
  },
  /**
   * 页面的初始数据
   */
  data: {
    userInfo: {}
  },
})

效果

作用三 : 生命周期函数 

在生命周期函数中,完成应用程序启动后的初始化操作

  • 比如登录操作
  • 比如读取本地数据(类似于token,然后保存在全局方便使用)
  • 比如请求整个应用程序需要的数据 

这里简单写写,详细的登录操作在下方

// app.js
App({
  // globalData
  globalData: {
    userState: {
      openId: '',
      sessionKey: '',
      unionId: ''
    },
    userInfo: {}
  },
  // 页面初始化调用的回调函数
  onLaunch(options) {
    // 从本地获取用户状态信息,判断是否需要登录
    const userState = wx.getStorageSync('userState')
    // 如果不存在,则进行登录
    if (!userState || !userState.openId) {
      wx.login({
        success: res => {
          console.log('code =>', res.code);
          // 发送 res.code 到后台换取 openId, sessionKey, unionId
          this.getUserState(res.code)
        }
      })
    }
  },
  // 获取用户信息
  getUserState(code) {
    wx.request({
      // 填入请求地址
      url: 'url',
      code,
      success: (res) => {
        const { openId, unionId, sessionKey, userInfo } = res
        // 将登录成功的数据,保存在storage中
        wx.setStorageSync('userState', {
          openId,
          unionId,
          sessionKey,
        })
        wx.setStorageSync('userInfo', userInfo)

        // 将登录成功的数据,保存在globalData中
        this.globalData.userState = {
          openId,
          unionId,
          sessionKey,
        }
        this.globalData.userInfo = userInfo
      }
    })
    // 
  }
})

五、注册页面 – Page函数 - (page).js

小程序中的每个页面, 都有一个对应的js文件, 其中调用 Page函数 注册页面示例

 

网址 : Page(Object object) | 微信开放文档

  • 在注册时, 可以绑定初始化数据、生命周期回调、事件处理函数等

注册Page页面时,一般做如下事情 : 

  • 在生命周期函数中发送网络请求,从服务器获取数据
  • 初始化一些数据,以方便被wxml引用展示
  • 监听wxml中的事件,绑定对应的事件函数
  • 其他一些监听(比如页面滚动、上拉刷新、下拉加载更多等)

0. 生命周期

网址 : 生命周期 | 微信开放文档

1. 发送网络请求

// logs.js
Page({
  data: {
    pagaData: {}
  },
  // 页面加载时促发
  onLoad() {
    const _this = this
    // 发送网络请求
    wx.request({
      url: 'www.baidu.com',
      success: (res) => {
        console.log(this, res);
        this.setData({
          pagaData: res.pagaData || {}
        })
      },
      error(err) {
        console.log(_this, err);
      }
    })
  }
})

2. 初始数据

// logs.js
Page({
  data: {
    // 定义初始化数据
    movies: ['葫芦娃大战喜羊羊', '蜡笔小新殴打图图'],
  },
  // 页面加载时促发
  onLoad() { }
})

3. 绑定事件函数

wxml

<!--logs.wxml-->
<view>
  <button bindtap="handClick">事件触发</button>
  <button>------</button>
  <button bindtap="clickQuery"
          data-query="abc">触发并传递参数</button>
  <button>------</button>
  <button wx:for="{{btns}}"
          wx:key="*this"
          bindtap="btnsClick"
          data-index="{{index}}"
          data-item="{{item}}"
          style="background-color: {{item}};">
    {{item}} - {{index}}
  </button>
</view>

js

// logs.js
Page({
  data: {
    // 定义初始化数据
    btns: ['red', 'blue', 'green', 'pink', 'yellow'],
  },
  // 页面加载时促发
  onLoad() { },
  // 绑定事件
  handClick() {
    console.log('我被点击了');
  },
  // 传递参数
  clickQuery(e) {
    console.log('我被点击了,参数是 : ', e.target.dataset);
  },
  btnsClick(e) {
    console.log('循环出的按钮', e.target.dataset);
  }
})

4. 其他的监听

01 - 下拉刷新

        logs.json

{
  "usingComponents": {},
  // 开启下拉刷新
  "enablePullDownRefresh": true
}

        logs.js

// logs.js
Page({
  data: {
  },
  // 监听用户下拉刷新
  onPullDownRefresh() {
    console.log('用户下拉刷新');
    // 模拟网络请求
    setTimeout(() => {
      // api: 停止下拉刷新
      wx.stopPullDownRefresh({
        success: (res) => {
          console.log('成功关闭下拉刷新', res);
        },
        fail: (err) => {
          console.log('关闭失败', err);
        }
      })
    }, 1000);
  }
})

        效果

02 - 上拉加载更多

        logs.json

{
  "usingComponents": {},
  // 页面上拉触底事件触发时距页面底部距离,单位为px
  // 距离底部多少距离,触发
  "onReachBottomDistance": 100
}

        logs.js

// logs.js
Page({
  data: {
    // 默认展示50条数据
    countsNum: 50,
    // 到达底部后,需要增加的数量
    countsSize: 40
  },
  // 监听页面是否滚动到达底部
  onReachBottom() {
    this.setData({
      // 到达底部后,增加
      countsNum: this.data.countsNum + this.data.countsSize
    })
    console.log('滚动到底部');
  }
})

        logs.wxml

<!--logs.wxml-->
<view wx:for="{{countsNum}}" wx:key="*this">
  页面数据 : {{item}}
</view>

        效果

03 - 页面滚动

// logs.js
Page({
  data: {
    // 定义初始化数据
    btns: ['red', 'blue', 'green', 'pink', 'yellow'],
  },
  // 页面加载时促发
  onLoad() { },

  // 页面滚动
  onPageScroll(e) {
    console.log(e); // 距离顶部的距离
  },
})

六、常见的内置组件

Text : 文本组件

Text组件 : 用于显示文本, 类似于span标签, 是行内元

text | 微信开放文档

<!-- 基本用法 -->
<text>Hello world</text>

<!-- 使用js中定义的数据 -->
<text>{{message}}</text>

<!-- 长按可选择,可用来复制 -->
<text user-select>{{message}}</text>

<!-- 解码 -->
<text decode>&gt;</text>

Button : 按钮组件

Button组件用于创建按钮,默认块级元素

button | 微信开放文档

基本用法

<!-- 默认 => 独占一行 -->
<button>按钮</button>

<!-- size属性 => 变成了inline-block -->
<button size="mini">size属性</button>

<!-- type属性 => 可更改背景、颜色 -->
<button size="mini"
        type="default">文字颜色变绿</button>
<button size="mini"
        type="primary">背景颜色变绿</button>
<button size="mini"
        type="warn">文字颜色变红</button>

<!-- plain => 镂空效果 -->
<button size="mini"
        plain> 镂空效果,有边框 </button>

<!-- 禁用 -->
<button size="mini"
        disabled> 禁止交互 </button>

<!-- 加载效果 => 前方有个小圆圈在转,可动态绑定 -->
<button size="mini"
        loading='{{true}}'> 等待加载 </button>

open-type属性

open-type用户获取一些特殊性的权限,可以绑定一些特殊的事件

        获取用户信息

                wxml

<!-- 获取用户信息 -->
<button bindtap="getUserProfile">获取用户信息</button>

                js

Page({
  getUserProfile(e) {
    // 推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
    // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({
      desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      // 点击允许
      success: (res) => {
        console.log('success', res);
      },
      // 点击拒绝
      fail: (err) => {
        console.log('fail', err);
      }
    })
  }
})

        获取用户手机

                wxml

<!-- 获取用户手机号 -->
<button open-type="getPhoneNumber"
        bindgetphonenumber="getPhoneNumber">获取用户手机号</button>

                js

Page({
  getPhoneNumber(e) {
    // 如果点击了拒绝
    if (e.target.errMsg !== 'getPhoneNumber:ok') {
      return wx.showToast({
        title: '用户未同意授权手机号',
        icon: 'none'
      })
    }
    // 如果点击确认
    cosnt { code, encryptedData, iv } = e.target
    // 把数据传给后端,后端会去解密拿到手机号的
    wx.request({
      url: 'https://example.com/onLogin',
      data: {
        appId: '',
        openId: '',
        code,
        encryptedData,
        iv
      },
      method: "post",
      success: function (res) {
        console.log(res);
      }
    })
  }
})

View : 视图组件

View视图组件 : 块级元素,独占一行,通常用作容器组件,和div差不多

view | 微信开放文档

ScrollView滚动组件

scroll-view : 可以实现局部滚动

scroll-view | 微信开放文档

上下滚动

        wxml

<!-- 固定高度,上下滚动,( y轴 : scroll-y ) -->
<scroll-view class="contain scroll-y"
             scroll-y
             bindscrolltoupper="scrollTop"
             bindscrolltolower="scrollBottom"
             bindscroll='scrollIng'>
  <block wx:for="{{viewColors}}"
         wx:key="*this">
    <view class="box"
          style="background-color: {{item}}">
      {{item}}
    </view>
  </block>
</scroll-view>

        css

.contain {
  height: 300px;
}

.box {
  height: 100px;
  color: white;
  font-weight: bold;
}

        js

Page({
  data: {
    viewColors: ['red', 'pink', 'green', 'blue']
  },
  scrollTop() {
    console.log('到达顶部');
  },
  scrollBottom() {
    console.log('到达底部');
  },
  // 滚动中触发
  scrollIng({ detail }) {
    console.log(detail);
  }
})

左右滚动

注 : 若要开启flex布局,须加上enable-flex这个属性

        wxml

<!-- 固定宽度,左右滚动,( x轴 : scroll-x ) -->
<scroll-view class="contain scroll-x"
             scroll-x
             enable-flex
             bindscrolltoupper="scrollLeft"
             bindscrolltolower="scrollRight"
             bindscroll='scrollIng'>
  <block wx:for="{{viewColors}}"
         wx:key="*this">
    <view class="box"
          style="background-color: {{item}}">
      {{item}}
    </view>
  </block>
</scroll-view>

        css

.contain {
  display: flex;
}

.box {
  /* 不压缩 */
  flex-shrink: 0;
  width: 150px;
  height: 150px;
  color: white;
  font-weight: bold;
}

        js 

Page({
  data: {
    viewColors: ['red', 'pink', 'green', 'blue']
  },
  scrollLeft() {
    console.log('到达左侧');
  },
  scrollRight() {
    console.log('到达右侧');
  },
  // 滚动中触发
  scrollIng({ detail }) {
    console.log(detail);
    // detail.deltaX > 0,往左滚动
    // detail.deltaX < 0,往右滚动
  }
})

Image : 图片组件

Image组件 : 用于显示图片

image | 微信开放文档

基本使用 

<!-- image : 默认自带宽度和高度 => 320 * 240 -->

<!-- 根目录 : / 表示根目录,有些地方能用,有些不行 -->
<!-- <image src="/assets/images/zznh.png" /> -->

<!-- 加载本地图片 -->
<image src="../../assets/images/zznh.png" />
<!-- 加载网络图片 -->
<image src="https://uploadfile.bizhizu.cn/up/9d/8d/1e/9d8d1e3fba7895d13a639f464ef147b1.jpg.source.jpg" />

<!-- 使用mode属性 -->
<image src="../../assets/images/zznh.png" mode="widthFix" />


使用手机本地图片 wx.chooseMedia

        wxml

<!-- 选择手机本地图片,将本地图片展示出来 -->
<button bindtap="choseImage"
        type="primary">进入相册选择图片</button>

<image wx:if="{{imgUrl}}"
       src="{{imgUrl}}"
       style="width: 100%;"
       mode="widthFix" />

        js 

Page({
  data: {
    imgUrl: ''
  },
  choseImage() {
    // 选择本地图片
    wx.chooseMedia({
      // 最多可以选择的文件个数
      count: 1,
      // 只能拍摄图片或从相册选择图片
      mediaType: 'image',
    }).then(res => {
      if (res.errMsg !== 'chooseMedia:ok') return
      console.log(res);
      const imageList = res.tempFiles || []
      const imgUrl = imageList[0].tempFilePath || ''
      this.setData({
        imgUrl
      })
    })
  }
})

Input : 组件

model:value => 双向绑定功能

wxml

<input type="text" model:value='{{message}}' />

js

Page({
  data: {
    message: 'abc'
  },
})

组件的共同属性

七、小程序基础语法

1. Wxss

01 - 样式写法

页面样式的三种写法:行内样式、页面样式、全局样式

优先级依次是:行内样式 > 页面样式 > 全局样式

02 - 选择器

权重

03 - 尺寸单位

rpx(responsive pixel): 可以根据屏幕宽度进行自适应,规定屏幕宽为750rpx

在iphone6上,屏幕宽度为375px,共有750个物理像素,1px === 2rpx

iphone6为标准,设计稿是375,1px === 2rpx  => 设计稿16px,我们写32rpx

iphone6为标准,设计稿是750,1px === 1rpx  => 设计稿20px,我们写20rpx

.view {
  /* 在375的设计稿中,200rpx === 100px */
  width: 200rpx;
  height: 200rpx;
  background-color: blue;
  line-height: 200rpx;
  text-align: center;
  color: #fff;
}

2. Wxml

01 - 逻辑判断

wx:if --- wx:elif --- wx:else

<view>
  <text wx:if="{{counter >= 90}}">优秀</text>
  <text wx:elif='{{counter >= 60}}'>及格</text>
  <text wx:else>不及格</text>
</view>

02 - hidden

hidden属性:

  • hidden是所有的组件都默认拥有的属性
  • 当hidden属性为true时, 组件会被隐藏
  • 当hidden属性为false时, 组件会显示出来

hidden和wx:if的区别

hidden => 控制隐藏和显示是控制是否添加hidden属性,相当于display:none

wx:if => 是控制组件是否渲染的

03 - block

block : 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性

  • 将需要进行遍历或者判断的内容进行包裹
  • 将遍历和判断的属性放在block便签中,不影响普通属性的阅读,提高代码的可读性 

04 - 列表渲染

        wx:for

index : 遍历后在wxml中可以使用一个变量index,保存的是当前遍历数据的下标值

item : 数组中对应某项的数据

<!-- 遍历一个数组 => a,b,c -->
<view wx:for="{{['a','b','c']}}"
      wx:key="*this">{{item}} --- {{index}}</view>

<!-- 遍历一个字符串 => p,o,i,p,o,i -->
<view wx:for="{{'poipoi'}}"
      wx:key="item">{{item}} --- {{index}}</view>

<!-- 遍历数字 => 0 - 9 -->
<view wx:for="{{10}}"
      wx:key="*this">{{item}} --- {{index}}</view>

        item - index

wx:for-item = ' '    =>   item 重命名

wx:for-index = ' '  =>   index 重命名

<view wx:for="{{['a','b','c']}}"
      wx:for-item='str'
      wx:for-index='key'
      wx:key="*this">{{str}} --- {{key}}</view>

        key

使用wx:for时,可以添加一个key来提供性能

wx:key 的值以两种形式提供 :

  • 字符串  =>  代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能 动态改变
  • 保留关键字 *this  =>  代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字 

3. Wxs

01 - 概念

WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构

为什么要设计WXS语言

  • 在WXML中是不能直接调用Page/Component中定义的函数的 (  底层没有进行封装 )
  • 但是某些情况, 我们可以希望使用函数来处理WXML中的数据(类似于Vue中的过滤器),这个时候就使用WXS了

WXS使用的限制和特点 : 

  • WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行
  • WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序 提供的API
  • 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备 上二者运行效率 无差异
  • 最好使用ES6之前的语法,否则可能会有问题

02 - 写法

WXS有两种写法  :写在标签中 || 写在以.wxs结尾的文件中

WXS标签的属性 : 

wxs : 

  • 每一个 .wxs 文件和 标签都是一个单独的模块
  • 每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见
  • 一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现 

        写法一 : 直接写在标签内

<!-- 1. 定义wxs标签,设定模块名 -->
<wxs module="format">
  // 2. 定义函数
  function priceFormat(price) {
    return price + '元'
  }
  // 3. 导出 : 必须导出后,才能被使用,且必须被CommonJs导出
  module.exports = {
    priceFormat: priceFormat
  }
</wxs>

<!-- 4. 使用 : 使用模块名.函数 => 进行使用 -->
<view wx:for="{{['111','222','333']}}"
      wx:for-item='money'
      wx:for-index='key'
      wx:key="*this">{{format.priceFormat(money)}}</view>
<!-- 5. 输出 : 111元、222元、333元 -->

        写法二 : 独立的文件,通过src引入

                定义format.wxs

// 1. 定义函数
function priceFormat(price) {
  return price + '元'
}
// 2. 导出 : 必须导出后,才能被使用,且必须被CommonJs导出
module.exports = {
  priceFormat: priceFormat
}

                wxml

<!-- 3. 定义wxs标签,设定模块名,引入wxs文件 -->
<wxs module="format" src='./format.wxs' />

<!-- 4. 使用 : 使用模块名.函数 => 进行使用 -->
<view wx:for="{{['111','222','333']}}"
      wx:for-item='money'
      wx:for-index='key'
      wx:key="*this">{{format.priceFormat(money)}}</view>
<!-- 5. 输出 : 111元、222元、333元 -->

八、小程序的事件处理

1. 组件事件类型

某些组件会有自己特性的事件类型

input : bindinput  ||  bindblur  ||  bindfocus

scroll-view : bindscrolltowpper  ||  bindscrolltolower

2. 事件对象event

当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中

01 - currentTarget && target

target : 触发事件的元素

currentTarget : 处理事件的元素(大部分情况使用target)

        wxml

<view id="outer" class="outer" bindtap="outerClick">
  <view id="inner" class="inner">
  </view>
</view>

        wxss

.outer {
  width: 400rpx;
  height: 400rpx;
  background-color: #0f0;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 100rpx auto;
}

.inner {
  width: 150rpx;
  height: 150rpx;
  background-color: #00f;
}

        js

Page({
  outerClick(e) {
    console.log(e);
    // target : 触发事件的元素 => 点击的是蓝色,所以 target === inner
    console.log('target:', e.target);
    // currentTarget : 处理事件的元素 => 冒泡到外层了,所以 currentTarget === outer
    console.log('currentTarget:', e.currentTarget);
  }
})

02 - touches && changedTouches

touches : 当前屏幕上有多少个手指

changedTouches : 较上一个状态,改变了多少个手指

        区别一 : touchend中不同

        区别二 : 多手指触摸时不同

03 - 事件参数的传递

方式一  :  使用data-*

方式二  :  使用mark ( 2.7.1版本以上 )  =>    事件 | 微信开放文档

data- : 需要区分currnetTarget 和 target,一般使用currnetTarget即可

mark : 会自动合并所有的mark数据,不受影响

        wxml

<view id="outer"
      class="outer"
      bindtap="outerClick"
      data-name='coder'
      data-age='18'
      mark:address='地球🌍'>
  <text mark:know='是的'>传递</text>
</view>

        js

Page({
  outerClick(e) {
    // 通过data- : 传递过来的数据
    const { name, age } = e.currentTarget.dataset
    console.log(name, age);
    // 通过mark : 传递过来的数据,子组件和父组件mark数据会合并
    console.log(e.mark); // { know: "是的", address: "地球🌍" }
    const { address } = e.mark
    console.log(address);
  }
})

04 - 事件参数的传递的例子

        wxml

<view class="nav">
  <block wx:for="{{dataList}}"
         wx:key="*this">
    <view class="item"
          bindtap="itemClick"
          data-index='{{index}}'>
      <text class="text {{currentIndex === index ? 'active' : '' }}">{{item}}</text>
    </view>
  </block>
</view>

        wxss

.nav {
  display: flex;
  align-items: center;
  height: 100rpx;
}

.item {
  flex: 1;
  text-align: center;
}

.text {
  display: inline-block;
  padding-bottom: 10rpx;
  border-bottom: 6rpx solid #fff;
}

.active {
  border-bottom-color: orange;
}

        js

Page({
  data: {
    dataList: ['衣服👔', '裤子👖', '鞋子🥿'],
    currentIndex: 0
  },
  itemClick(e) {
    // 注意,这个时候使用currentTarget,才能拿到传递过来的参数
    // 如果不这么做,那么点到文字上就不会进行切换
    const { index } = e.currentTarget.dataset
    this.setData({
      currentIndex: index
    })
  }
})

        效果

3. 事件冒泡 && 事件捕获

事件捕获 : 从外到内

事件冒泡 : 从内到外

总是先捕获,再冒泡

  • bind : 继续传递
    • bind*   =>   冒泡监听到后继续传递
    • capture-bind*     =>   捕获监听到后继续传递
  • catch : 停止传递
    • catch*   =>   冒泡监听到后即停止,不传递 
    • capture-catch*   =>   捕获到后即停止,不传递

4. 获取元素的宽高等

const query = wx.createSelectorQuery()
query.select('.swiper-item-layout').boundingClientRect()
query.exec((res) => {
  const winWid = wx.getSystemInfoSync().windowWidth // 获取当前屏幕的宽度
  const height = res[0].height  // 获取元素的高度
  const width = res[0].width // 获取元素的宽度
  const swiperHeight = height / width * winWid + 'px' // 等比例设置值
  this.swiperHeight = swiperHeight
})

九、小程序的组件化开发

1. 概念

小程序刚刚推出时,是不支持组建化的,1.6.3版本后开始支持

组件化思想的应用 : 

  • 尽可能的将页面拆分成一个个小的、可复用的组件
  • 让代码更加方便组织和管理,并且扩展性也更强

2. 创建并使用组件

01 - 创建

02 - 配置

需要在 json 文件中进行自定义组件声明

将component 字段设为 true 可这一组文件设为自定义组件

03 - 引入组件

        局部注册组件

在页面的json文件中,配置usingComponents,即可在页面中使用

        全局注册组件

app.json的usingComponents声明某个组件,那么所有页面和组件可以直接使用该组件

04 - 使用组件

<view>
  <!-- 使用即可 -->
  <main-list />
</view>

05 - 注意事项

  • 自定义组件也是可以引用自定义组件
    • 使用usingComponents 字段
  • 自定义组件和页面所在项目根目录名 不能以“wx-”为前缀
    • 否则会报错

3. 组件的样式细节

01 - 组件内的样式 对 外部样式 的影响

组件内的class样式 : 只对组件wxml内的节点生效, 对于引用组件的Page页面不生效

ps : 组件内不能使用id选择器、属性选择器、标签选择器 => 因为会作用到外面,不安全

02 - 外部的样式 对 组件内样式 的影响

外部使用class的样式 : 只对外部wxml的class生效,对组件内是不生效的
ps :

外部使用了id选择器、属性选择器不会对组件内产生影响
外部使用了标签选择器,会对组件内产生影响

03 - 如何让class可以相互影响

在Component对象中,可以传入一个options属性

其中options属性中有一个styleIsolation(隔离)属性

styleIsolation有三个取值 : 

  • isolated(默认取值,取隔离即可
    • 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响
  • apply-shared
    • 表示页面的样式将影响到自定义组件,但自定义组件中的样式不会影响页面
  • shared
    • 表示页面的样式将影响到自定义组件,自定义组件的样式也会影响页面和其他设置
  • ......
// pages/logs/components/mainList.js
Component({
  options: {
    // 1. 默认值,相互不影响
    // styleIsolation: "isolated",

    // 2. 页面可以影响组件内部,组件内部不能影响页面
    // styleIsolation: "apply-shared",

    // 3. 相互都能影响
    styleIsolation: "shared",
  }
})

4. 组件的通信

01 - 向组件传递数据 - properties

可以使用 properties 属性

  • 支持的类型
    • String、Number、Boolean、Object、Array、null(不限制类型)
  • 默认值
    • 通过value设置默认值

        页面定义

<view>
  <!-- 使用组件 -->
  <main-list title='我要飞的更高!!!' />
</view>

        组件接收

// pages/logs/components/mainList.js
Component({
  properties: {
    // 传递过来的数据
    title: {
      type: "String",
      value: '我是默认的'
    }
  }
})

02 - 向组件传递样式 - externalClasses

说实话,有点繁琐,咕噜咕噜~

        页面定义

        页面传递

        组件接收

        组件使用

03 - 组件向外传递事件

        组件定义

        组件传递

        页面监听

        页面处理

 04 - 页面直接调用组件方法

可在父组件里调用 this.selectComponent ,获取子组件的实例对象

调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")

ps : 如果有多个,可以使用 this.selectAllComponents

        组件定义

// pages/logs/components/mainList.js
Component({
  data: {
    dataList: ['衣服👔', '裤子👖', '鞋子🥿'],
    currentIndex: 0
  },
  // 绑定的方法
  methods: {
    itemClick(e) {
      const { index } = e.currentTarget.dataset
      this.setData({
        currentIndex: index
      })
      this.triggerEvent('itemClick', index)
    },
    // 定义一个方法
    textFun() {
      console.log('我是组件的方法!');
    }
  }
})

        页面定义

<view>
  <!-- 使用组件,定义一个选择器,这里用class -->
  <main-list class="main-list-ref"
             bind:itemClick='itemClick' />
</view>

        页面使用

Page({
  itemClick(params) {
    const { detail: index } = params
    console.log(index);
  },
  onShow() {
    // 1. 获取自定义组件实例,通过类选择器
    const mainListRef = this.selectComponent('.main-list-ref')
    // 2. 调用自定义组件方法
    mainListRef.textFun()
    // 3. 获取自定义组件数据
    console.log(mainListRef.data.dataList); // ["衣服👔", "裤子👖", "鞋子🥿"]
  }
})

5. 组件的插槽

小程序的插槽不支持默认值

01 - 单个插槽

        组件

<view class="box">
  <view class="header">header</view>

  <view class="content">
    <!-- 定义插槽 -->
    <!-- 注 : 当没有传进来东西时,这里不会显示 -->
    <slot></slot>
  </view>

  <view class="footer">footer</view>
</view>

        页面

<view>
  <!-- 使用组件时,在标签中间写的内容会传递到slot中 -->
  <main-list>123</main-list>

  <main-list>
    <!-- 使用组件时,在标签中间写的内容会传递到slot中 -->
    <button>a</button>
  </main-list>

  <main-list>
    <!-- 使用组件时,在标签中间写的内容会传递到slot中 -->
    <text>冲啊!</text>
  </main-list>

</view>

        效果

02 - 具名插槽

        组件定义

<view class="box">
  <view class="left">
    <!-- 插槽名称为left -->
    <slot name='left'></slot>
  </view>
  <view class="center">
    <!-- 插槽名称为center -->
    <slot name='center'></slot>
  </view>
  <view class="right">
    <!-- 插槽名称为right -->
    <slot name='right'></slot>
  </view>
</view>

        组件配置

// pages/logs/components/mainList.js
Component({
  options: {
    // 开启使用多个插槽 => 具名插槽
    multipleSlots: true
  }
})

        页面使用

<view>
  <main-list>
    <!-- 使用左侧的插槽 -->
    <view slot='left'>A</view>
  </main-list>
  <main-list>
    <!-- 使用中间的插槽 -->
    <view slot='center'>B</view>
  </main-list>
  <main-list>
    <!-- 使用右边的插槽 -->
    <text slot='right'>冲啊!</text>
  </main-list>
</view>

03 - 解决默认值问题

小程序的插槽不支持默认值        =>        可以用css的empty伪类 + 兄弟选择器来解决

        组件

<view class="box">
  <view class="header">header</view>

  <view class="content">
    <!-- 注 : 当没有传进来东西时,这里不会显示 -->
    <slot></slot>
  </view>
  <!-- 当插槽无内容时,默认显示 -->
  <view class="default">
    哈哈哈哈,我是默认
  </view>

  <view class="footer">footer</view>
</view>

        样式

/* 默认 隐藏默认值 */
.default {
  display: none;
}

/* 当插槽为空时,显示  =>  运用empty伪类 + 兄弟选择器 */
.content:empty+.default {
  display: block;
}

6. 组件中的混入 - behaviors

behaviors 是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins”

  • 每个 behavior 可以包含一组属性、数据、生命周期函数和方法
  • 组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用
  • 每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior

01 - 共享的代码

// 创建一个Behavior并导出
export const counterBehaviors = Behavior({
  // 定义数据
  data: {
    count: 10
  },
  // 接收参数
  properties: {},
  // 引入其他behaviors
  behaviors: [],
  // 定义方法
  methods: {
    text() {
      console.log('text');
    }
  }
})

02 - 组件中使用

// 1. 倒入behaviors
import { counterBehaviors } from '../../../behaviors/counter'

Component({
  // 2. 组件使用behaviors
  behaviors: [counterBehaviors]
})

7. 组件的生命周期

01 - 概念

组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发

ps : 最重要的生命周期是 created attached detached

组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高) 

Component({
  // 生命周期写在这里面
  lifetimes: {
    // 组件实例被创建,可以用来进行网络请求
    created() {
      console.log('created');
    },
    // 组件实例进入页面节点树中
    attached() {
      console.log('attached');
    },
    // 组件渲染布局完成后
    ready() {
      console.log('ready');
    },
    // 组件被移除时
    detached() {
      console.log('detached');
    }
  }
})

02 - 组件所在页面的生命周期

一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理

组件所在页面的生命周期  =>  在 pageLifetimes 定义段中定义

Component({
  // 组件生命周期
  lifetimes: {
    created() {
      console.log('created'); // 1
    },
    attached() {
      console.log('attached'); // 2
    },
    ready() {
      console.log('ready'); // 4
    },
    detached() {
      console.log('detached');
    }
  },
  // 组件所在页面的生命周期
  pageLifetimes: {
    show() {
      console.log('show', '组件所在页面被展示时执行'); // 3
    },
    hide() {
      console.log('hide', '组件所在页面被隐藏时执行');
    },
    resize(e) {
      console.log('resize', '组件所在页面尺寸变化时执行', e);
    }
  }
})

8. 组件Component构造器总结图

十、小程序系统API调用

1. 网络请求

微信提供了专属的API接口,用于网络请求: wx.request(Object object)

网址 : RequestTask | 微信开放文档

01 - API参数

02 - API使用

Page({
  data: {
    dataList: []
  },
  onLoad() {
    wx.request({
      // 请求地址
      url: 'https://www.baidu.com/',
      // 不管是post还是get,请求参数都是放到data中的
      data: {
        age: 18
      },
      // 请求成功的回调
      success: (res) => {
        const data = res.data.data
        console.log(data);
        this.setData({
          dataList: data
        })
      },
      // 请求失败的回调
      fail: (err) => {
        console.log(err);
      }
    })
  }
})

03 - API封装

        封装成函数

                封装

export function request(option) {
  return new Promise((resolve, reject) => {
    wx.request({
      ...option,
      success: (res) => {
        resolve(res.data)
      },
      fail: reject
    })
  })
}

                使用

// 1. 导入
import { homeDataList } from '../../service/request/home/index'

Page({
  data: {
    dataList: []
  },
  async onLoad() {
    const params = {
      url: 'https://www.baidu.com/',
      data: {
        age: 18
      }
    }
    // 2. 直接使用
    homeDataList(params).then(res => {
      console.log('res', res);
    }).catch(err => {
      console.log('err', err);
    })

    // 3. 使用async/await
    const dataList = await homeDataList(params)
    console.log(dataList);
  }
})

        封装成类

                封装

class request {
  // 设置baseUrl
  constructor(baseUrl) {
    this.baseUrl = baseUrl
  }
  // 封装 request 方法
  request(option) {
    const { url } = option
    return new Promise((resolve, reject) => {
      wx.request({
        ...option,
        // 拼接地址
        url: this.baseUrl + url,
        success: (res) => {
          resolve(res.data)
        },
        fail: reject
      })
    })
  }
  // 封装 get 方法
  get(option) {
    return this.request({ ...option, method: 'GET' })
  }
  // 封装 post 方法
  post(option) {
    return this.request({ ...option, method: 'POST' })
  }
}

// 可创建多个实例,请求不同的地址
export const starRequest = new request('https://www.baidu.com')

                使用

04 - 网络请求域名配置

每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信

小程序登录后台 – 开发管理 – 开发设置 – 服务器域名

配置时需要注意 : 

  • 域名只支持 https
    • wx.request、wx.uploadFile、wx.downloadFile 和 wss (wx.connectSocket) 协议
  • 域名不能使用 IP 地址
    • 小程序的局域网 IP 除外 或 localhost
  • 端口
    • 配置端口
      • 如 https://myserver.com:8080,但是配置后只能向 https://myserver.com:8080 发起请求。如果向https://myserver.com、https://myserver.com:9091 等 URL 请求则会失败
    • 不配置端口
      • 如 https://myserver.com,那么请求的 URL 中也不能包含端口,甚至是默认的 443 端口也不可以。如果向 https://myserver.com:443 请求则会失败
  • 域名必须经过 ICP 备案
  • 不支持配置父域名,使用子域名

2. 展示弹窗效果

01 - showToast

​​​​​​showToast 和 showLoading 只能同时显示一个

        效果

        代码

wx.showToast({
  // 提示内容
  title: 'title',
  // 图标 => none error loading success
  icon: 'success',
  // 自定义图标 => 自定义图标的本地路径,image 的优先级高于 icon
  image: '/assets/images/tabbar/cart_active.png',
  // 持续时间
  duration: 2000,
  // 是否显示透明蒙层,显示期间不能进行交互
  mask: true,
  // 成功回调
  success: (res) => {
    console.log('展示成功', res);
  },
  // 失败回调
  fail: (err) => {
    console.log('展示失败', err);
  },
  // 接口调用结束的回调函数(调用成功、失败都会执行)
  complete: (data) => {
    console.log('展示', data);
  }
})

02 - showLoading

和 showToast => icon为loadind,展示的效果相同

但是可以手动控制关闭弹窗的时间

        效果

        代码

wx.showLoading({
  // 提示内容
  title: '加载中',
  // 是否显示透明蒙层,显示期间不能进行交互
  mask: true,
  // 成功回调
  success: (res) => {
    console.log('展示成功', res);
  },
  // 失败回调
  fail: (err) => {
    console.log('展示失败', err);
  },
  // 接口调用结束的回调函数(调用成功、失败都会执行)
  complete: (data) => {
    console.log('展示', data);
  }
})

// 两秒后,关闭弹窗 => 可在请求数据完成后,再调用该方法
setTimeout(function () {
  wx.hideLoading()
}, 2000)

03 - showModal

        效果

        代码

wx.showModal({
  // 提示的标题
  title: '你有钱吗',
  // 提示的内容
  content: '我有',
  // 是否显示取消按钮
  showCancel: true,
  // 取消按钮的文字,最多 4 个字符
  cancelText: '骗你哒',
  // 取消按钮的文字颜色,必须是 16 进制格式的颜色字符串
  cancelColor: '#f0f',
  // 确认按钮的文字,最多 4 个字符
  confirmText: '真的啦',
  // 确认按钮的文字颜色,必须是 16 进制格式的颜色字符串
  confirmColor: '#00f',
  // 是否显示输入框
  // editable: true,
  // 显示输入框时的提示文本
  // placeholderText: '我是提示内容',
  // 成功回调
  success: (res) => {
    /**
     * content	=> 	editable 为 true 时,用户输入的文本
     * confirm	=>	为 true 时,表示用户点击了确定按钮
     * cancel	  =>	为 true 时,表示用户点击了取消
     */
    if (res.confirm) {
      console.log('用户点击确定')
    } else if (res.cancel) {
      console.log('用户点击取消')
    }
  },
  // 失败回调
  fail: (err) => {
    console.log('展示失败', err);
  },
  // 接口调用结束的回调函数(调用成功、失败都会执行)
  complete: (data) => {
    console.log('展示', data);
  }
})

04 - showActionSheet

        效果

        代码

wx.showActionSheet({
  // 警示文案
  alertText: '你有钱吗',
  // 按钮的文字数组,数组长度最大为 6
  itemList: ['吃饭', '喝水', '打豆豆', '睡觉'],
  // 按钮的文字颜色
  itemColor: '#0f0',
  // 成功回调
  success: (res) => {
    /**
     * tapIndex	=>	用户点击的按钮序号,从上到下的顺序,从0开始
     */
    console.log('展示成功', res, res.tapIndex);
  },
  // 失败回调,监听取消
  fail: (err) => {
    console.log('展示失败', err);
  },
  // 接口调用结束的回调函数(调用成功、失败都会执行)
  complete: (data) => {
    console.log('展示', data);
  }
})

3. 分享功能 onShareAppMessage

分享是小程序扩散的一种重要方式,小程序中有两种分享方式,通过 onShareAppMessage

此事件处理函数需要 return 一个 Object,用于自定义转发内容

方式一

点击右上角的菜单按钮,之后点击转发

直接配置 onShareAppMessage 方法即可

Page({
  onShareAppMessage() {
    return {
      title: '我是标题', // 分享后显示的标题
      path: '/pages/logs/logs', // 分享后打开的路径,别人打开的页面的路径
      imageUrl: '/assets/images/tabbar/cart_active.png' // 分享后显示的图片
    }
  }
})

方式二

监听用户点击页面内转发按钮   =>   button 组件 open-type="share"

页面设置后,再配置 onShareAppMessage 方法即可

// wxml
<view>
  <button open-type="share">分享</button>
</view>


// js
Page({
  onShareAppMessage() {
    return {
      title: '我是标题', // 分享后显示的标题
      path: '/pages/logs/logs', // 分享后打开的路径,别人打开的页面的路径
      imageUrl: '/assets/images/tabbar/cart_active.png' // 分享后显示的图片
    }
  }
})

4. 获取设备信息 wx.getSystemInfo

获取当前设备的信息,用于手机信息或者进行一些适配工作

wx.getSystemInfo(Object object)

Page({
  onShow() {
    wx.getSystemInfo({
      success: (res) => {
        console.log('success', res);
      },
      fail: (err) => {
        console.log('fail', err);
      },
      complete: (res) => {
        console.log('complete', res);
      },
    })
  }
})

5. 获取位置信息 wx.getLocation

对于用户的关键信息,比如获取用户的位置信息,需要获取用户的授权后才能获得

01 - 授权

在app.json中进行配置

地址 : 全局配置 | 微信开放文档

{
  "pages": [
    "pages/index/index"
  ],
  // 配置权限
  "permission": {
    // 配置位置权限
    "scope.userLocation": {
      // 弹出框中显示的内容
      "desc": "我需要你的位置信息,马上给我"
    }
  },
  "window": {
  },
  "tabBar": {
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}

02 - 获取

Page({
  onShow() {
    wx.getLocation({
      type: 'wgs84', // wgs84 返回 gps 坐标
      altitude: false,// 传入 true 会返回高度信息,但是会减慢接口返回速度
      isHighAccuracy: true, // 开启高精度定位
      highAccuracyExpireTime: 5000,// 高精度定位超时时间(ms),指定时间内返回最高精度,该值3000ms以上高精度定位才有效果
      // 接口调用成功的回调函数
      success: (res) => {
        /**
         * latitude	=>	纬度,范围为 -90~90,负数表示南纬
         * longitude	=>	经度,范围为 -180~180,负数表示西经
         * speed	=>	速度,单位 m/s,看当前设备是否在移动
         * accuracy	=>	位置的精确度,反应与真实位置之间的接近程度,可以理解成10即与真实位置相差10m,越小越精确
         * altitude	=>	高度,单位 m
         * verticalAccuracy	=>	垂直精度,单位 m(Android 无法获取,返回 0)
         * horizontalAccuracy	=>	水平精度,单位 m
         */
        console.log('success', res);
      },
      // 接口调用失败的回调函数
      fail: (err) => {
        console.log('fail', err);
      },
      // 接口调用结束的回调函数(调用成功、失败都会执行)
      complete: (res) => {
        console.log('complete', res);
      },
    })

  }
})

6. Storage存储

01 - 同步

存储的代码执行完后,才会继续往后执行

也就是说,下一行代码就能获取到存储的值

Page({
  onShow() {
    // 存
    wx.setStorageSync('name', 'coder')
    wx.setStorageSync('age', 18)
    wx.setStorageSync('array', [1, 2, 3, 4])
    wx.setStorageSync('Object', { friends: '小明' })
    // 取
    console.log(wx.getStorageSync('name')); // coder
    // 删
    wx.removeStorageSync('name')
    // 清空
    wx.clearStorageSync()
  }
})

02 - 异步

不影响其他代码执行   =>   存储后,不能立马获取到值 

Page({
  onShow() {
    // 存
    wx.setStorage({
      key: 'name',
      data: "coder",
      encrypt: true, // 2.21.3 => 若开启加密存储,setStorage 和 getStorage 需要同时声明 encrypt 的值为 true
      success: ({ errMsg }) => {
        console.log(errMsg); // setStorage:ok
      }
    })
    // 取
    wx.getStorage({
      key: 'name',
      encrypt: true, // 2.21.3 => 若开启加密存储,setStorage 和 getStorage 需要同时声明 encrypt 的值为 true
      success: ({ errMsg, data }) => {
        console.log(errMsg, data); // getStorage:ok => coder
      }
    });
    // 删
    wx.removeStorage({
      key: 'name',
      success: ({ errMsg }) => {
        console.log(errMsg); // removeStorage:ok
      }
    })
    // 清空
    wx.clearStorage({
      success: ({ errMsg }) => {
        console.log(errMsg); // clearStorage:ok
      }
    })
  }
})

十一、页面跳转

1. 通过wx的API跳转

00 - switchTab - 跳转到 tabBar 页面

跳转到 tabBar 页面

并关闭其他所有非 tabBar 页面,使用 navigateBack 无法退回

// 跳转页面
wx.switchTab({
  url: '/pages/text/text',
  success: (res) => { console.log('success', res); },
  fail: (err) => { console.log('fail', err); },
  complete: (res) => { console.log('complete', res); },
})

01 - navigateTo - 普通页面跳转

保留当前页面,跳转到应用内的某个页面

但是不能跳到 tabbar 页面

// index页面
Page({
  // 监听方法
  handleClick() {
    const name = 'coder'
    const age = 19
    // 跳转页面
    wx.navigateTo({
      // 地址 ?后面为携带的参数
      url: `/pages/jump1/jump1?name=${name}&age=${age}`,
    })
  }
})

// ---------------------------------------------------------------------------

// pages/jump1/jump1.js
Page({
  // 接受从index页面跳转过来时接受到的参数
  onLoad(option) {
    console.log(option); // {name: "coder", age: "18"}
  }
})

02 - navigateBack - 页面返回

wx.navigateBack(Object object)   =>   关闭当前页面,返回上一页面或多级页面

Page({
  onShow() {
    setTimeout(() => {
      // 页面返回
      wx.navigateBack({
        // 默认返回上一页,可以设定
        delta: 1
      })
    }, 3000);
  }
})

03 - 页面跳转 - 数据传递(一)

在界面跳转过程中需要相互传递一些数据

        首页 => 详情页

使用URL中的query字段 

// index
Page({
  handleClick() {
    const name = 'coder'
    const age = 19
    // 跳转页面
    wx.navigateTo({
      url: `/pages/jump1/jump1?name=${name}&age=${age}`,
    })
  }
})

        详情页 => 首页

在详情页内部拿到首页的页面对象,直接修改数据

// jump1页面
Page({
  onShow() {
    setTimeout(() => {
      // 页面返回
      wx.navigateBack({
        // 默认返回上一页,可以设定
        delta: 1
      })
    }, 3000);
  },
  // 拿到传递过来的数据
  onLoad(option) {
    console.log(option);
  },
  /**
   * 写在这里的理由 : 用户可能点击顶部状态栏中的返回键,写在这不管怎么返回,都会触发
   */
  // 页面被注销时调用
  onUnload() {
    // 1. 获取到已经存在的所有页面
    const pages = getCurrentPages()
    // 2. 拿到上一个页面的实例  当前页面为最后一个,所以上一个页面是减2
    const prePage = pages[pages.length - 2]
    // 3. 直接设置值
    prePage.setData({ message: 'ccc' })
  }
})

04 - 页面跳转 - 数据传递(二)

在小程序基础库 2.7.3 开始支持events参数,也可以用于数据的传递

        首页 => 详情页

使用URL中的query字段进行传递,定义events对象

// index页面
Page({
  // 监听方法
  handleClick() {
    const name = 'coder'
    const age = 19
    // 跳转页面
    wx.navigateTo({
      url: `/pages/jump1/jump1?name=${name}&age=${age}`,
      // 使用该参数
      events: {
        // 设置方法名 => 在子组件中调用该方法,传递数据过来
        acceptData(data) {
          console.log('acceptData', data); // {name:'coder'}
        },
        // 设置方法名
        acceptOtherData(data) {
          console.log('acceptOtherData', data); // {age:18}
        }
      }
    })
  }
})

        详情页 => 首页

使用eventChanner,传递数据到上一个页面

// jump1页面
Page({
  onShow() {
    setTimeout(() => {
      // 页面返回
      wx.navigateBack({
        // 默认返回上一页,可以设定
        delta: 1
      })
    }, 3000);
  },
  // 拿到传递过来的数据
  onLoad(option) {
    console.log(option);
  },
  /**
   * 写在这里的理由 : 用户可能点击顶部状态栏中的返回键,写在这不管怎么返回,都会触发
   */
  // 页面被注销时调用
  onUnload() {
    // 1. 拿到eventChanner渠道
    const eventChanner = this.getOpenerEventChannel()
    // 2. 通过渠道,拿到回调函数,并且传递数据给上一个页面
    eventChanner.emit('acceptData', {
      name: 'coder'
    })
    eventChanner.emit('acceptOtherData', {
      age: 18
    })
  }
})

2. 通过navigator组件

navigator组件主要就是用于界面的跳转的,也可以跳转到其他小程序中

01 - 跳转到 tabBar 页面

<navigator open-type="switchTab" url="/pages/logs/logs">跳转</navigator>

02 - 跳转到 普通 页面

<navigator url="/pages/jump1/jump1?name=123">跳转</navigator>

03 - 返回 上一个 页面

<navigator open-type="navigateBack" delta="1">跳转</navigator>

十二、小程序登录解析

1. 概念

01 - openid

openid : 当 在小程序 用微信功能登录时,每个微信都具备唯一标识openid

可把 openid 保存到数据库中,即使用户更换了手机,也能通过 openid 识别为同一用户

02 - unionid

unionid : 在微信的不同产品之间可用来识别是否为同一用户

小程序的 openid 和 公众号的 openid,可能是不一样的,但是unionid一样

03 - 用户身份多平台共享 

再开一个页面或窗口   =>    进行账号绑定 || 手机号绑定

openid - unionid - 手机号 => 就建立了联系

2. 登录流程

3. 代码

登录操作

可以写到 app.js 的 onLaunch 中

也可以写到 页面.js 的 onLoad 中

Page({
  /**
   * onLoad登录操作
   */
  onLoad() {
    // 1. 判断token是否有值
    const token = wx.getStorageSync('token') || ''
    // 2. 判断token是否过期
    // ......

    // 有值 且 没过期
    if (token && '没过期') {
      // 做其他操作
    } else {
      // 3. 获取code
      this.requestCode()
    }
  },
  // 登录获取code
  requestCode() {
    wx.login({
      success: ({ code }) => {
        // 4. 将code发给后端
        this.requestBack(code)
      },
    })
  },
  // 将code发给后端
  requestBack(code) {
    console.log(code);
    wx.request({
      url: 'https://www.baidu.com',
      data: { code },
      method: 'POST',
      success: (res) => {
        // 5. 拿到身份标识( 自定义登录态 ),可能不会返回openid, unionid,看后端
        const { openid, unionid, token } = res.data
        // 6. 把 自定义登录态 存入storage
        wx.setStorageSync('token', token)
      },
    })
  }
})

十三、代码上传到Gitee

git操作都是大同小异,详细的可以看我之前写的git文章

 

网址 : 版本控制工具 之 Git_玄鱼殇的博客

1. 创建远程仓库

2. 配置远程仓库

01 - 本地点击版本管理

02 - 添加远程仓库

03 - 设置用户名和邮箱

04 - 设置网络和认证

3. 推送代码到远程仓库

01 - 首次推送

02 - 修改后推送

        推送到本地仓库

        拉取远程仓库代码

        推送到远程仓库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/344990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python Paramiko stdout 多进程 阻塞 卡住 问题解决

使用paramiko进程远程操作时&#xff0c;如果缓冲区满了&#xff0c;exec_command在写入该缓冲区时会产生阻塞并一直保持阻塞状态&#xff0c;直到缓冲区被清空为止。 使用multiprocessing无疑会加重这种情况&#xff0c;其中一种解决办法是设置exec_command的get_pty参数为Tru…

商城业务:购物车

人生在世如身处荆棘之中&#xff0c;心不动&#xff0c;人不妄动&#xff0c;不动则不伤&#xff1b;如心动则人妄动&#xff0c;伤其身痛其骨&#xff0c;于是体会到世间诸般痛苦。 1、购物车需求 1&#xff09;、需求描述&#xff1a; - 用户可以在登录状态下将商品添加到购…

【项目】---快速搜索工具

目录 一、项目背景 二、项目需求分析 三、项目涉及的知识点 四、项目实现的基础理论 五、项目框架 六、增加系统工具模块 6.1、扫描本地的文件的功能 七、增加数据管理模块 7.1、先了解数据库sqlite 7.2 封装sqlite数据库管理类 7.3、封装数据管理类 7.3.1增加搜索…

成都女子情人节给东莞男子送巧克力,却被后者典当后换成望京卡牌

一年一度的情人节已经来临&#xff0c;每年的这个时候&#xff0c;都是少男少女们欢庆的节日&#xff0c;因为他们可以借助送礼物&#xff0c;各自表达对另一半的爱慕之情。然而由于中国人的传统观念&#xff0c;一般都是男方给女方送礼物&#xff0c;女方给男方送礼物的就凤毛…

宝塔搭建实战php开源likeadmin通用管理移动端uniapp源码(四)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 上一期给大家分享了pc端的部署方式&#xff0c;今天来给大家分享uniapp端在本地搭建&#xff0c;与打包发布到宝塔的方法。感兴趣的朋友可以自行下载学习。 技术架构 vscode node16 vue3 uniapp vite types…

PageHelper分页查询

分页查询分页查询的优点所谓分页,就是查询结果数据较多时,采用按页显示的方法,而不是一次性全部显示分页的优点:服务器:一次性查询所有信息,服务器压力大,分页查询服务器压力小客户端:一次性显示所有信息,需要更多流量,加载时间也会更长,分页显示没有这个问题用户体验上:一般最…

Hot 100 | 287. 寻找重复数

LeetCode 287. 寻找重复数 给定一个包含 n 1 个整数的数组 nums &#xff0c;其数字都在 [1, n] 范围内&#xff08;包括 1 和 n&#xff09;&#xff0c;可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数 &#xff0c;返回 这个重复的数 。 你设计的解决方案必须&…

【Spring Cloud Alibaba】(三)OpenFeign扩展点实战 + 源码详解

系列目录 【Spring Cloud Alibaba】&#xff08;一&#xff09;微服务介绍 及 Nacos注册中心实战 【Spring Cloud Alibaba】&#xff08;二&#xff09;微服务调用组件Feign原理实战 本文目录系列目录前言一、Feign扩展点配置二、OpenFeign扩展点配置1. 通过配置文件配置有效范…

二维码数据压缩实践 | 使用python对二维码数据进行压缩 |不乱码,支持中文

当前二维码的应用越来越广泛&#xff0c;包括疫情时期的健康码也是应用二维码的典型案例&#xff0c;最近需要通过一张二维码显示较多文本数据&#xff0c;也就是对二维码数据进行压缩&#xff0c;使用CSDN搜索了半天居然没有能简单使用的代码&#xff0c;很多事例代码解决不了…

机器连接和边缘计算

以一种高效、可扩展的方式进行连接和边缘计算的结合&#xff0c;解决了在工业物联网应用中的机器数据集成问题。 一 边缘计算 边缘计算描述了由中央平台管理的数据分散式处理。边缘计算对于工业物联网而言非常重要。在许多应用程序中&#xff0c;由于数据量非常大&#xff0c;…

C++STL剖析(十)—— 位图(bitset)

文章目录1. 位图的介绍2. 位图的概念3. 位图的实现&#x1f351; 构造函数&#x1f351; 设置指定位&#x1f351; 清除指定位&#x1f351; 获取指定位的状态&#x1f351; 打印函数4. 总结1. 位图的介绍 在介绍位图之前先来看一道面试题吧 给 40 亿个不重复的无符号整数&…

【网络原理2】---TCP协议的格式

传输层重点协议TCP 协议TCP 协议段格式TCP内部的工作机制1. 确认应答2.超时重传TCP 协议 TCP 协议相对于 UDP 是复杂不少的。 在网络编程这里已经讲了 TCP 的特点&#xff1a; 有链接 可靠传输 面向字节流 全双工 可靠传输 是 TCP内部的机制&#xff0c;和编码关系不大&#x…

[oeasy]python0083_十进制数如何存入计算机_八卦纪事_BCD编码_Binary_Coded_Decimal

编码进化 回忆上次内容 上次 研究了 视频终端的 演化 从VT05 到 VT100从 黑底绿字 到 RGB 24位真彩色形成了 VT100选项 从而 将颜色 数字化 了 生活中我们更常用 10个数字 但是 计算机中 用二进制 日常计数的十进制数 是如何存储进计算机的呢?&#x1f914; 从10进制到2进…

Java学习笔记-03(API阶段-2)集合

集合 我们接下来要学习的内容是Java基础中一个很重要的部分&#xff1a;集合 1. Collection接口 1.1 前言 Java语言的java.util包中提供了一些集合类,这些集合类又称之为容器 提到容器不难想到数组,集合类与数组最主要的不同之处是,数组的长度是固定的,集合的长度是可变的&a…

思科网络部署,(0基础)入门实验,超详细

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的绽放&#xff0…

如何让一起打拼的员工有持续的动力

我们的工作都要靠团队的每一个人努力&#xff0c;如何持续让老员工也能有持续的动力完成任务是我们非常重要的管理目标。 方法一&#xff1a;提供稀缺的学习机会。很多企业的培训都是针对新员工或者管理层的&#xff0c;容易让老员工意识不到自己应该学习&#xff0c;接触不到新…

Echarts 雷达图设置拐点大小和形状,tooltip后文字不居中对齐

第017个点击查看专栏目录Echarts的雷达图的拐点大小和形状是可以设置的&#xff0c;在series中设置symbol 相应的属性即可。 使用tooltip的时候&#xff0c;默认状态文字是居中对齐的&#xff0c;不好看。需要在tooltip属性中设置一下&#xff0c;如图所示&#xff0c;效果比较…

记录robosense RS-LIDAR-16使用过程4

一、时隔一个月&#xff0c;再次记录激光雷达的使用&#xff0c;一个月不碰生疏了好多&#xff0c;如鲠在喉&#xff0c;先来个基本操作熟悉一下找找感觉。连接在线雷达&#xff1a;https://github.com/RoboSense-LiDAR/rslidar_sdk/blob/main/doc/howto/06_how_to_decode_onli…

selenium--验证码识别,一文教会你回答面试官

相信大家在日常划水&#xff0c;培训&#xff0c;工作中都遇到这样的问题&#xff0c;验证码怎么处理&#xff1f;也有一些面试官会这么问。这里大致的说说&#xff0c;最常见的处理方式。1、万能验证码&#xff1a;所谓的万能验证码也就是找开发固定一个验证码&#xff0c;比如…

jenkins下配置maven

1. 先在jenkins服务器上安装maven 下载-解压-重命名-启动 [rootVM-0-12-centos local]# wget https://mirrors.aliyun.com/apache/maven/maven-3/3.9.0/binaries/apache-maven-3.9.0-bin.tar.gz [rootVM-0-12-centos local]# tar xf apache-maven-3.9.0-bin.tar.gz [rootVM-0…