当前位置:   article > 正文

小程序学习 - 01小程序简介+微信小程序基础_.stamp.app.js.map

.stamp.app.js.map

小程序简介

小程序是一个全新的、轻量级的移动端应用。

起源

在小程序出现之前的移动端开发的解决方案有:

  • Android
  • iOS
  • Windows Phone - 后来退出历史舞台

移动端开发发展了一段时间之后也暴漏出来一些问题,传统 App (Android / iOS)的开发和运营成本很高:

  • 开发一款 App,就要开发这两个版本,既要招 Android 工程师,也要招 iOS 工程师,人力成本非常高
  • App 开发完成之后,还要发版,即发布到应用商店中(例如 App Store)。发版申请提交之后要等待审核,审核不通过就需要退回调整重新发版,发版过程繁琐
  • 发版完成后还需要推广,常规做法是花钱在应用商店打广告,提高 App 的排名

为了解决传统 App 的这些问题,小程序应运而生。

发展历程

最早推出小程序的是微信团队。

  • 2016 年 1 月 9 日,小程序立项
  • 2016年 9 月 21 日,开始内测
  • 2017 年 1 月 9 日,正式上线

小程序上线之后取得了巨大的成功,这导致一些其它平台也跟风上线了小程序的内容,如支付宝、京东、今日头条、百度。

微信小程序推出的最早且目前最有影响力(后文默认介绍微信小程序)。

优势

  • 相比原生 App (Android / iOS),小程序无需单独下载
    • 只需要扫一扫或搜一下即可打开使用
  • 小程序寄宿在 App 中,宿主 App 自带流量,所以小程序推广成本低
    • 例如 2017 年的“跳一跳”,利用朋友圈成绩排名,迅速爆红
  • 小程序简单易学
    • Android 工程师要学习 Android 开发和 Java
    • iOS 工程师要学习 Objective-C 或 Swift
    • 小程序只需要掌握前端技术栈

小程序与传统网页开发的区别

小程序的运行环境与网页开发不同:

  • 网页开发的运行环境是浏览器
  • 小程序的运行环境是操作系统(Android / iOS)上的 App 客户端
    • 如微信小程序的运行环境是微信客户端

所以小程序与网页开发有一些区别:

  • 小程序中不能使用 HTML
  • 小程序中可以使用 CSS
  • 小程序主要开发语言是 JavaScript
    • 但是 BOM(操作 HTML) 和 DOM(与浏览器交互) 在小程序中不可用
    • 基于 DOM 和 BOM 的 JS 库也不能用,如 jQuery

运行环境

在这里插入图片描述

小程序的运行环境主要有两个:

  • 渲染层 - 主要用于渲染内容和样式
  • 逻辑层 - 主要用来处理 JS

不同的操作系统,内部的支持也不一样:

运行环境逻辑层渲染层
iOSJSCoreWKWebView
AndroidV8 引擎Chromium 定制内核

虽然不同操作系统的渲染机制和逻辑不一样,但外部的表现是一样的。

微信小程序基础

下面通过案例学习微信小程序的基础使用,主要包括:

  1. 注册小程序账号
  2. 搭建开发环境
  3. 初始化小程序 - 类似脚手架工具生成基础代码

注册小程序账号

在小程序官网注册:https://mp.weixin.qq.com/wxopen/waregister?action=step1

注意:注册过微信公众号的邮箱,不能再注册微信小程序账号

也可以申请测试号,免注册快速体验小程序开发(不能发布)。

注册成功后,可以在后台获取小程序的 AppID,它是小程序的唯一标识。

搭建开发环境

去小程序官网,下载安装微信开发者工具:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

详细界面介绍参考官网文档:界面

初始化小程序

打开微信开发者工具新建小程序项目:

在这里插入图片描述

“不使用模板” 与 “JavaScript - 基础模板” 基本没区别。

本文创建的项目:

  • 项目名称:start
  • AppID:注册 AppID
  • 开发模式:小程序
  • 后端服务:不使用云服务
  • 语言:JavaScript
  • 模板:不使用模板

解读初始化项目

下面依次解读小程序初始化项目:

  1. 目录结构
  2. 生命周期
  3. app 代码
  4. index 页面
  5. logs 页面

目录结构

官方文档:

全局文件

全局文件存放在根目录,文件名是固定的,不能修改,其中包括:

  • app.js - 小程序入口文件,启动小程序首先加载这个文件
  • app.json - 小程序全局配置
  • app.wxss - 小程序全局样式,类似网页开发的 css

页面文件

页面文件存放在 pages 文件夹下,初始包括 index 和 logs 两个页面,每个页面由四个文件组成,以 index 为例:

  • index.js - 页面入口(数据绑定和逻辑代码)
  • index.json - 页面配置,当前页面的页面级配置
  • index.wxml - 页面内容(组件+条件渲染),类似网页开发的 html
  • index.wxss - 页面样式,仅对当前页面有效的样式文件

需要注意的是:

  • 小程序的页面由 4 个文件组成:.js.json.wxml.wxss,四个文件的文件名必须一致
  • 小程序的页面不是由开发者手动创建的,而是由小程序自动生成的,只需要配置小程序全局配置文件 app.jsonpages,保存文件后就会自动创建页面文件

例如:

"pages": [
  // 未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)
  "pages/index/index",
  "pages/logs/logs",
   // pages 是页面存放目录
   // test 是页面存放的子目录
   // my-test 是页面文件名称
  "pages/test/my-test"
],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

生命周期

小程序生命周期主要指两个循环状态:前台到后台、初始化到销毁。

关于前后台的定义参考官方文档:小程序运行机制

小程序中的生命周期有两类:

  • 小程序生命周期(全局生命周期):声明在 app.js 文件中
  • 页面生命周期:声明在页面的入口文件 <pagename>.js

小程序生命周期函数

常用小程序生命周期函数及触发时机:

  • onLaunch - 小程序初始化,小程序冷启动时触发,全局只调用一次
  • onShow - 初始化完成小程序热启动,或从后台切换到前台时触发
  • onHide - 从前台切换到后台时触发

测试案例

// app.js
App({
  onLaunch() {
    console.log('onLaunch - 小程序加载')
    // 默认初始代码...
  },
  onShow() {
    console.log('onShow - 小程序显示')
  },
  onHide() {
    console.log('onHide - 小程序隐藏')
  },
  globalData: {
    userInfo: null
  }
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

保存文件后,小程序会重新初始化,依次触发 onLaunchonShow

可点击工具栏上的 切后台 切换到后台触发 onHide

PS:如果工具栏没有 切后台 按钮,可以通过 工具 - 工具栏管理 设置显示的工具栏图标。

页面生命周期函数

常用页面生命周期函数及触发时机:

  • onLoad - 页面加载时触发,整个页面生命阶段只执行依次
  • onShow - 页面显示或切换到前台时触发
  • onReady - 页面准备就绪(首次渲染完毕)时触发,整个页面生命阶段只执行依次
  • onHide - 页面隐藏或切换后台时触发
  • onUnload - 页面销毁(切换页面)时触发

测试案例

修改 test 页面的生命周期函数

// pages/test/test.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log('onLoad - 页面加载')
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    console.log('onReady - 页面就绪')
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    console.log('onShow - 页面显示')
  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
    console.log('onHide - 页面隐藏')
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    console.log('onUnload - 页面卸载')
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  },

  /**
   * 重载页面
   */
  goIndex: function() {
    // 调用原生 API 重新加载页面
    wx.reLaunch({
      url: "/pages/index/index"
    })
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

添加重载功能:

<!--pages/test/test.wxml-->
<text bindtap="goIndex">跳转到 index</text>

  • 1
  • 2
  • 3

配置小程序的底部导航栏 tabBar,用于切换页面:

{
  "pages": [
    "pages/index/index",
    "pages/logs/logs",
    "pages/test/test"
  ],
  // 窗口配置
  "window": {
    "backgroundTextStyle": "light",
    // 顶部导航栏背景
    "navigationBarBackgroundColor": "#fff",
    // 顶部导航栏标题
    "navigationBarTitleText": "Weixin",
    // 顶部导航栏文字颜色
    "navigationBarTextStyle": "black"
  },
  // 底部导航配置
  "tabBar": {
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页"
      },
      {
        "pagePath": "pages/logs/logs",
        "text": "日志"
      },
      {
        "pagePath": "pages/test/test",
        "text": "测试"
      }
    ]
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json",
  "lazyCodeLoading": "requiredComponents"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

在这里插入图片描述

上面的空白是图标预留,可以自行配置 iconPathselectedIconPath

现在点击导航栏切换页面,查看控制台输出:

  • onShow 在 onReady 前执行
  • 切换页面会触发 onShow 和 onHide
  • 切换后台时,先触发页面的 onHide 再触发小程序的 onHide
  • 切换前台时,先触发小程序的 onShow 再触发页面的 onShow

微信小程序的启动流程

官方文档 - 生命周期 中有一张图分别介绍了 View(视图)和 AppService(App 服务)两个线程的生命周期顺序:

在这里插入图片描述

综合小程序和页面的生命周期就是微信小程序的启动流程:

  • 首先执行小程序生命周期 onLaunch
  • 然后执行小程序生命周期 onShow
  • 接着执行页面生命周期 onLoad,执行完成后页面就加载出来了
  • 接着执行页面生命周期 onShow 显示页面
  • 请求数据执行完成后,就会执行页面生命周期 onReady
  • onReady 执行完成后,如果切换后台就会执行页面生命周期 onHide
  • onHide 执行完成后,就会执行小程序生命周期 onHide
  • 如果执行页面卸载 onUnload,页面就会被销毁
  • 此时如果再访问另一个页面,就会执行这个页面的 onLoad,重复上面的调用过程

微信原生 API

小程序开发框架提供了丰富的微信原生 API,这些 API 存放在云端(服务器端),不需要自己开发和部署。

除了一些 web API,还提供了一些移动端的 API,只能在移动端调用,如:

  • 拍照:调用摄像头,返回照片信息
  • 扫一扫:识别二维码内容

原生 API 通过 wx.<api> 调用,详细参考 API 文档

代码解析

app.js

// app.js
App({
  onLaunch() {
    console.log('onLaunch - 小程序加载')
    // 展示本地存储能力
    // 同步方式获取本地缓存数据
    const logs = wx.getStorageSync('logs') || []
    // 添加当前启动时间
    logs.unshift(Date.now())
    // 同步方式设置本地缓存数据
    wx.setStorageSync('logs', logs)

    // 登录
    wx.login({
      success: res => {
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
      }
    })
  },
  onShow() {
    console.log('onShow - 小程序显示')
  },
  onHide() {
    console.log('onHide - 小程序隐藏')
  },
  // 全局数据
  globalData: {
    // 旧版初始化的项目将用户信息保存在这里
    // 新版初始化的项目将用户信息保存在 index.js 中
    userInfo: null
  }
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

以前的版本会在 onLaunch 内部调用 wx.getSettings 获取用户当前设置,根据返回的数据判断授权状态,如果用户已授权,则调用 wx.getUserInfo 获取用户信息。

现在更改为在 pages/index/index.js 中调用的 wx.getUserProfile,每次请求都会弹出授权窗口,用户同意后返回 userInfo

pages/index/index.js

初始化项目默认启动获取用户信息,可将 canIUseOpenData 设置 false 变更为手动获取:小程序启动后页面会显示 获取头像昵称,点击请求 wx.getUserProfile

// index.js
// 获取应用实例
// 获取的是 app.js 中生成的小程序的实例
const app = getApp()

Page({
  // 绑定数据,类似 vue 的 data
  data: {
    motto: 'Hello World',
    userInfo: {},
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo'),
    canIUseGetUserProfile: false,
    canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName') // 如需尝试获取用户信息可改为false
  },
  // 事件处理函数
  bindViewTap() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
  onLoad() {
    if (wx.getUserProfile) {
      // 修改数据
      this.setData({
        canIUseGetUserProfile: true
      })
    }
  },
  getUserProfile(e) {
    // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({
      desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      success: (res) => {
        console.log(res)
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    })
  },
  getUserInfo(e) {
    // 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
    console.log(e)
    this.setData({
      userInfo: e.detail.userInfo,
      hasUserInfo: true
    })
  }
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

WXML

官方文档:

WXML(WeiXin Markup Language) 是框架设计的一套标签语言。

  • WXML 相当于小程序中的模板引擎
  • WXML 中展示内容的具体标签,称为组件
    • 数据绑定
    • 数据展示(条件渲染、列表渲染)
  • WXML 与组件之间的关系,就相当于 HTML 与标签
作用小程序组件HTML 标签
展示区块viewdiv
展示图片imageimg
展示文本textp
链接导航navigatora

模板

WXML 的模板可以定义代码片段,在不同地方中调用。

使用 <template> 定义模板,使用 <import> 引用模板,使用 is 声明需要使用的模板名称,使用 data 传入模板所需的数据。

注意:如果 app.json 配置了 "lazyCodeLoading": "requiredComponents",开发者工具中使用了 <import> 引入模板的页面会显示白屏,因为项目开启了按需注入,但真机预览中会正常显示,开发时可以将该配置项删除。

代码解析

pages/index/index.wxml

<!--index.wxml-->
<view class="container">
  <view class="userinfo">
    <!-- wx:if 是 WXML 的条件渲染语法 -->
    <!-- 使用数据或表达式的语法是 {{}} -->
    <block wx:if="{{canIUseOpenData}}">
      <!-- bindtap 是事件属性,值是需要绑定的处理函数的名称 -->
      <!-- 事件触发时会在该页面对应的 Page 中找到相应的事件处理函数 -->
      <!-- 小程序绑定事件处理函数只接受字符串,及处理函数名 -->
      <!-- 无法自定义调用方式或传参,如 bindtap="{{(e, 'params') => bindViewTap}}" -->
      <!-- 可以将参数绑定在标签上(如 data-param="value"),通过 event 获取 -->
      <view class="userinfo-avatar" bindtap="bindViewTap">
        <open-data type="userAvatarUrl"></open-data>
      </view>
      <open-data type="userNickName"></open-data>
    </block>
    <!-- 注意这里是 elif 而不是 elseif -->
    <block wx:elif="{{!hasUserInfo}}">
      <button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
      <button wx:elif="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
      <view wx:else> 请使用1.4.4及以上版本基础库 </view>
    </block>
    <block wx:else>
      <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
      <text class="userinfo-nickname">{{userInfo.nickName}}</text>
    </block>
  </view>
  <view class="usermotto">
    <text class="user-motto">{{motto}}</text>
  </view>
</view>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

pages/logs/logs.js

// logs.js
// 小程序中的模块化开发遵循 CommonJS 规范(exports 导出,require 导入)
const util = require('../../utils/util.js')

Page({
  data: {
    logs: []
  },
  onLoad() {
    // 获取日志并设置到 data 中
    this.setData({
      // 同步获取本地缓存
      logs: (wx.getStorageSync('logs') || []).map(log => {
        return {
          // 格式化时间
          date: util.formatTime(new Date(log)),
          timeStamp: log
        }
      })
    })
  }
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

pages/logs/logs.wxml

<!--logs.wxml-->
<view class="container log-list">
  <!-- 列表渲染 -->
  <block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
    <text class="log-item">{{index + 1}}. {{log.date}}</text>
  </block>
</view>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

pages/logs/logs.json

{
  // 优先级高于全局配置的导航标题
  "navigationBarTitleText": "查看启动日志",
  "usingComponents": {}
}
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/270674
推荐阅读
相关标签
  

闽ICP备14008679号