微信小程序开发-保姆式教程-入门篇

一,注册微信小程序

1.打开 微信公众平台

image.png


2.注册开发者账号

可以选择注册服务号/小程序号,如果有公司资质可选择注册服务号,在服务号里快速复用公司资质直接注册小程序号,一个服务号可以关联注册10个同主体或关联主体的小程序,3个非同主体小程序。

  • 服务号:企业资质,在服务号里可直接快速注册多个小程序号

  • 小程序:企业资质、个人资质···

注册需要用到的资料

  • 个人注册:身份证姓名、身份证号码、管理员手机、短信验证、管理员身份验证等等

  • 企业注册:企业类型、营业执照注册号、管理员身份证姓名、管理员身份证号码、管理员手机号码、短信验证等

注册账号.png

小程序注册

填写基本信息.png
激活.png
个人小程序.png
企业资质小程序.png


3.微信公众平台

注册完成后,既可登录微信公众平台,填写小程序信息、小程序类目,填写完整既可在设置中找到小程序AppId以及配置小程序秘钥。
在里面版本管理、成员管理、添加开发域名、管理插件、查看核心数据等,

微信公众平台.png


二,微信开发者工具

下载微信web开发者工具,根据自己的操作系统下载对应的安装包进行安装即可。

2.1.创建工程

  • 登录微信公众平台,填写好小程序信息后,去设置里面找到账号信息,找到小程序AppID
image.png
  • 打开微信开发者工具,点击加号创建工程
image.png
  • 填写好AppID等信息,选择工程模板,确定
image.png
  • 进入工程


    image.png


2.2.界面介绍

  • 微信开发工具界面


    image.png
  • 项目工程目录


    项目结构1.png


2.3 全局配置

小程序配置项 微信开发文档
小程序根目录下的 app.json 文件用来对微信小程序进行全局配置。文件内容为一个 JSON 对象

配置项
属性 类型 必填 描述 最低版本
entryPagePath string 小程序默认启动首页
pages string[] 页面路径列表
window Object 全局的默认窗口表现
tabBar Object 底部 tab 栏的表现
networkTimeout Object 网络超时时间
debug boolean 是否开启 debug 模式,默认关闭
functionalPages boolean 是否启用插件功能页,默认关闭 2.1.0
subpackages Object[] 分包结构配置 1.7.3
workers string Worker 代码放置的目录 1.9.90
requiredBackgroundModes string[] 需要在后台使用的能力,如「音乐播放」
plugins Object 使用到的插件 1.9.6
preloadRule Object 分包预下载规则 2.3.0
resizable boolean PC 小程序是否支持用户任意改变窗口大小(包括最大化窗口);iPad 小程序是否支持屏幕旋转。默认关闭 2.3.0
usingComponents Object 全局自定义组件配置 开发者工具 1.02.1810190
permission Object 小程序接口权限相关设置 微信客户端 7.0.0
sitemapLocation string 指明 sitemap.json 的位置
style string 指定使用升级后的weui样式 2.8.0
useExtendedLib Object 指定需要引用的扩展库 2.2.1
entranceDeclare Object 微信消息用小程序打开 微信客户端7.0.9
darkmode boolean 小程序支持 DarkMode 2.11.0
themeLocation string 指明 theme.json 的位置,darkmode为true为必填 开发者工具 1.03.2004271
lazyCodeLoading string 配置自定义组件代码按需注入 2.11.1
singlePage Object 单页模式相关配置 2.12.0
  • pages配置

用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json, .js, .wxml, .wxss 四个文件进行处理。

"pages": [
    "pages/index/index",
    "pages/next-bus/next-bus",
    "pages/park-map/park-map",
    "pages/park/park",
    "pages/route-info/route-info",
    "pages/glory-futian/glory-futian",
    "pages/glory-futian/details/vehicle-road/vehicle-road",
    "pages/glory-futian/details/station/station",
    "pages/glory-futian/details/smart-road/smart-road",
    "pages/glory-futian/details/slow/slow",
    "pages/bind-car/bind-car",
    "pages/offiaccount-login/offiaccount-login",
    "pages/construction/construction"
  ],
  • window配置

用于设置小程序的状态栏、导航条、标题、窗口背景色等。

属性 类型 默认值 描述
navigationBarBackgroundColor HexColor #000000 导航栏背景颜色,如 #000000
navigationBarTextStyle string white 导航栏标题颜色,仅支持 black / white
navigationBarTitleText string 导航栏标题文字内容
navigationStyle string default 导航栏样式,仅支持以下值:default 默认样式custom 自定义导航栏,只保留右上角胶囊按钮。参见注 2。
homeButton boolean default 在非首页、非页面栈最底层页面或非 tabbar 内页面中的导航栏展示 home 键
backgroundColor HexColor #ffffff 窗口的背景色
backgroundTextStyle string dark 下拉 loading 的样式,仅支持 dark / light
backgroundColorTop string #ffffff 顶部窗口的背景色,仅 iOS 支持
backgroundColorBottom string #ffffff 底部窗口的背景色,仅 iOS 支持
enablePullDownRefresh boolean false 是否开启全局的下拉刷新。
onReachBottomDistance number 50 页面上拉触底事件触发时距页面底部距离,单位为 px。
pageOrientation string portrait 屏幕旋转设置,支持 auto / portrait / landscape
restartStrategy string homePage 重新启动策略配置
initialRenderingCache string 页面初始渲染缓存配置,支持 static / dynamic
visualEffectInBackground string none 切入系统后台时,隐藏页面内容,保护用户隐私。支持 hidden / none
handleWebviewPreload string static 控制预加载下个页面的时机 支持 static / manual / auto
  • tabBar配置

客户端窗口的底部或顶部有 tab 栏可以切换页面,可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。

属性 类型 必填 默认值 描述
color HexColor tab 上的文字默认颜色,仅支持十六进制颜色
selectedColor HexColor tab 上的文字选中时的颜色,仅支持十六进制颜色
backgroundColor HexColor tab 的背景色,仅支持十六进制颜色
borderStyle string black tabbar 上边框的颜色, 仅支持 black / white
list Array tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab
position string bottom tabBar 的位置,仅支持 bottom / top
custom boolean false 自定义 tabBar

其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:

属性 类型 必填 说明
pagePath string 页面路径,必须在 pages 中先定义
text string tab 上按钮文字
iconPath string 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 positiontop 时,不显示 icon。
selectedIconPath string 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 positiontop 时,不显示 icon。
image.png
  • networkTimeout 网络请求超时配置

各类网络请求的超时时间,单位均为毫秒。


image.png
  • 分包加载加载

某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
整个小程序所有分包大小不超过 20M
单个分包/主包大小不能超过 2M

image.png

image.png


2.4 小程序页面配置

页面配置地址
小程序中,可以在页面对应的 .json 文件来对本页面的表现进行配置。如:导航栏样式、自定义组件注入等。

注意:app.json 中的部分配置,可以再页面对应的.json进行重新配置,页面中配置项在当前页面会覆盖 app.json 中相同的配置项。

配置项

属性 类型 默认值 描述
navigationBarBackgroundColor HexColor #000000 导航栏背景颜色,如 #000000
navigationBarTextStyle string white 导航栏标题颜色,仅支持 black / white
navigationBarTitleText string 导航栏标题文字内容
navigationStyle string default 导航栏样式,仅支持以下值:default 默认样式custom 自定义导航栏,只保留右上角胶囊按钮。
homeButton boolean false 在非首页、非页面栈最底层页面或非 tabbar 内页面中的导航栏展示 home 键
backgroundColor HexColor #ffffff 窗口的背景色
backgroundTextStyle string dark 下拉 loading 的样式,仅支持 dark / light
backgroundColorTop string #ffffff 顶部窗口的背景色,仅 iOS 支持
backgroundColorBottom string #ffffff 底部窗口的背景色,仅 iOS 支持
enablePullDownRefresh boolean false 是否开启当前页面下拉刷新
onReachBottomDistance number 50 页面上拉触底事件触发时距页面底部距离,单位为px
pageOrientation string portrait 屏幕旋转设置,支持 auto / portrait / landscape
disableScroll boolean false 设置为 true 则页面整体不能上下滚动。只在页面配置中有效,无法在 app.json 中设置
usingComponents Object 页面自定义组件配置
initialRenderingCache string 页面初始渲染缓存配置,支持 static / dynamic
style string default 启用新版的组件样式
singlePage Object 单页模式相关配置
restartStrategy string homePage 重新启动策略配置
handleWebviewPreload string static 控制预加载下个页面的时机。支持 static / manual / auto
visualEffectInBackground string 切入系统后台时,隐藏页面内容,保护用户隐私。支持 hidden / none,若对页面单独设置则会覆盖全局的配置
enablePassiveEvent Object或boolean 事件监听是否为 passive,若对页面单独设置则会覆盖全局的配置
renderer string 渲染后端


三、小程序语法

网页编程采用的是 HTML + CSS + JS 这样的组合,小程序也是如此 WXML + WXSS+ JS 。

3.1.wxml

和html没什么区别,只是标签名称不同。 多了一些表达式

<!-- 渲染 -->
<text>{{parkType}}</text>
<image data-text="{{index}}" bindtap="clickParkMap" class="item-poi" src="{{img_server_url}}/pos_icon.png"></image>
<view style="height:50rpx;">{{msg.length}}</view>

<!-- 条件渲染 -->
<block wx:if="{{selRegionIndex==1}}">
  <view class="select_result0">数据加载中···请稍后!</view>
</block>
<block wx:elif="{{selRegionIndex==2}}">
  <view class="select_result0">数据加载中···请稍后!</view>
</block>
<block wx:else>
  <view class="select_result0">数据加载中···请稍后!</view>
</block>

<!-- 列表渲染 -->
<view class="item" wx:for="{{selSort}}" wx:key="index" wx:for-index="index" wx:for-item="item" data-text="{{index}}" bindtap='selSort'>
  <text class="{{selSortIndex==index?'sel_text':''}}">{{item.name}}</text>
  <image wx:if="{{selSortIndex==index}}" src="{{img_server_url}}/radio_icon_sel.png"></image>
</view>

<!-- 引入过滤器 -->
<wxs module="filters" src="../../utils/filter.wxs"></wxs>
<!-- 使用过滤器 -->
<checkbox class="radio" color="#fff" wx:key="*this" wx:for="{{fieldsInfo.live_reason}}" wx:for-item="item" value="{{item}}" checked="{{ filters.setChecked(allData.live_reason,item) }}" >
  <text>{{item}}</text>
</checkbox>

<!-- 使用自定义组件 -->
<nav-bar header='{{nvabarData}}'></nav-bar>

<view>{{"hello" + name}}</view>

<template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>

<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
  • wxml模板使用
    定义item.wxml
<template name="item">
  <text>{{text}}</text>
</template>

使用模板

<!-- 引入 -->
<import src="item.wxml"/>
<!-- 使用 -->
<template is="item" data="{{text: 'forbar'}}"/>
  • include
    可以将目标文件除了 <template/> <wxs/> 外的整个代码引入,相当于是拷贝到 include 位置,
<!-- header.wxml -->
<view> header </view>

<!-- footer.wxml -->
<view> footer </view>

<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
=
<view> header </view>
<view> body </view>
<view> footer </view>
  • 注意事项
    当 wx:for 的值为字符串时,会将字符串解析成字符串数组
<view wx:for="array">
  {{item}}
</view>
=
<view wx:for="{{['a','r','r','a','y']}}">
  {{item}}
</view>
image.png

当花括号和引号之间如果有空格,将最终被解析成为字符串

<view wx:for="{{[1,2,3]}} ">
  {{item}}
</view>
=
<view wx:for="{{[1,2,3] + ' '}}" >
  {{item}}
</view>
image.png


3.2.wxss

WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改。
新增了单位尺寸:rpx

.body{
  width:100%;
  height:100%;
  background:rgba(243,247,249,1);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.top-panel{
  height:160rpx;
  padding:20rpx;
  border-radius:4px;
  position: relative;
}
/* 选项面板 */
.top-panel .sel-panel{
  height:calc( 100% - 40rpx );
  position: relative;
  padding:20rpx;
  background:rgba(255,255,255,1);
}
/* 输入 */
.top-panel .sel-panel .input-c{
  height:65rpx;
  display: flex;
  flex-direction: row;
  align-items: center;
}


3.3.wxs

小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。包含 wxs模块、变量、注释、运算符、语句、数据类型、基础类库

  • wxs文件定义
// /pages/tools.wxs 定义
var foo = "'hello world' from tools.wxs";
var bar = function (d) {
  return d;
}
module.exports = {
  FOO: foo,
  bar: bar,
};
module.exports.msg = "some msg";

  • wxs标签使用


    image.png
// 使用
<wxs src="./../tools.wxs" module="tools" />
<view> {{tools.msg}} </view>
<view> {{tools.bar(tools.FOO)}} </view>
  • 示例:
var filters = {
  // 设置复选框选中
  setChecked: function (selArr,fields) {
    if (selArr == null || selArr == undefined || selArr == '') {
      return false;  
    }
    if (selArr.indexOf(fields) != -1) {
      return true;
    } 
    return false;  
  },
  strToArr: function (strArr, index) {
    return strArr.split(',')[index];
  }
}

module.exports = {
  setChecked: filters.setChecked,
  strToArr: filters.strToArr
}
<!-- 引入过滤器 -->
<wxs module="filters" src="../../utils/filter.wxs"></wxs>

<view class="field-item">
  <checkbox-group class="radio-group-col" bindchange="radioChange" data-field="live_reason">
    <checkbox wx:key="*this" wx:for="{{fieldsInfo.live_reason}}" wx:for-item="item" value="{{item}}" checked="{{ filters.setChecked(allData.live_reason,item) }}" >
      <text>{{item}}</text>
    </checkbox>
  </checkbox-group>
</view>
image.png


3.4. js

  • 3.4.1 App.js

使用App()注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调、定义全局变量等。
全局变量如何使用后面会说。

//app.js
App({
  // 小程序初始化完成时触发,全局只触发一次
  onLaunch: function () {
    //获取手机导航栏高度
    wx.getSystemInfo({
      success: res => {
        var isIos = res.system.indexOf('iOS') > -1;
        this.globalData.statusHeight = res.statusBarHeight;
        this.globalData.navHeight = isIos ? 44 : 48;
        this.globalData.fontSize = res.fontSizeSetting;
        //设置低版本不显示自定义导航栏
        if (res.SDKVersion && res.SDKVersion.split('.')[0] * 1 <= 2 && res.SDKVersion.split('.')[1] * 1 < 5){
          this.globalData.navHeightHidden=true;
        }
      },
      fail(err) {
        console.log(err);
      }
    })
    // 位置授权
    wx.getSetting({
      success(res) {
        if (!res.authSetting['scope.userLocation']) {
          wx.authorize({
            scope: 'scope.userLocation',
            success() {}
          })
        }
      }
    })
  },
  // 监听小程序启动或切前台
  onShow (options) {
    // Do something when show.
  },
  // 监听小程序切后台
  onHide () {
    // Do something when hide.
  },
  // 错误监听函数。
  onError (msg) {
    console.log(msg)
  },
  // 页面不存在监听函数
  onPageNotFound(){
     // 小程序要打开的页面不存在时触发
  },
  // 未处理的 Promise 拒绝事件监听函数。
  onUnhandledRejection(){
    // 小程序有未处理的 Promise 拒绝时触发。
  },
  // 监听系统主题变化
  onThemeChange(){
    // 系统切换主题时触发。也可以使用 wx.onThemeChange 绑定监听
  },
  globalData: {
    //标题
    header:'交通行为与意愿调查系统',

    //自定义导航组件高度
    navHeightHidden:false,
    statusHeight:null,
    navHeight:null,
    fontSize:null,

    /**发布版-请求数据地址 */
    request_server_url: 'https://l***',
    /**开发版-请求数据地址本地 */
    // request_server_url: 'http:/***',

    /**发布版-图片地址 */
    img_server_url: 'https://***',  
    /**开发版-图片地址 */
    // img_server_url: '../../images',

    //地图相关
    selMap:null,
    mapKey: 'YPNBZ-PMSCX-G664V-7XBWG-SYFB6-KRBUO',
    referer: '深研居民调查',
    category: '生活服务,娱乐休闲',

    //用户信息
    openid:null,
    userInfo:null,
    surveyJob:false,

    //版本号
    version: 'v1.4.7',
  }
})


  • 3.4.2 页面page.js

使用Page() 注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

// pages/ceshi/ceshi.js
// 引入公用函数
const Common = require("../../utils/common.js");
//获取应用实例
const app = getApp();
Page({
  /**
   * 页面的初始数据
   */
  data: {
    // 图片链接
    img_server_url: app.globalData.img_server_url,
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

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

  },

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

  },

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

  }
})


  • 3.4.3 数据绑定使用
<!-- index.wxml-->
<text wx:if="{{text}}">{{text}}</text>

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

<view wx:for="{{persons}}" wx:key="*this" wx:for-index="index" wx:for-item="item">
  <view class="item-person" data-value="{{item.value}}" bindtap="setCheck">
    <text>{{item.name}}</text>
    <text>{{item.value}}</text>
  </view>
</view>

// index.js
// 获取应用实例
const app = getApp()
Page({
  data: {
    text:null,
    active:1,
    list:[
      { name:'',value:'' },
      { name:'',value:'' },
      { name:'',value:'' },
    ]
  },
  
  onShow: function () {
    this.setData({
      text:11
    })
  },
  // 事件处理函数
  setCheck(e) {
    var value = e.currentTarget.dataset.value;
    this.setData({
      active:value,
      text:'1111'
    })
  }
})


  • 3.4.4 事件介绍
  • 事件列表

  • 点击事件(单击):tap
  • 长按事件:longpress、longtap
  • 键盘输入事件:input
  • 回车事件:confirm
  • 输入框聚焦:focus
  • 输入框失焦:blur
  • value改变事件:change
  • 触摸动作开始:touchstart
  • 触摸动作结束:touchend
  • 触摸过程移动:touchmove
  • 触摸动作被打断:touchcancel
  • 提交表单事件:submit
  • 重置表单事件:reset
  • 事件对象属性列表

  • BaseEvent基础事件对象属性列表

属性 类型 说明
type String 事件类型
timeStamp Integer 事件生成时的时间戳
target Object 触发事件的源组件的一些属性值集合
currentTarget Object 当前组件的一些属性值集合
  • CustomEvent 自定义事件对象属性列表(继承 BaseEvent)
属性 类型 说明
detail Object 额外的信息
  • TouchEvent 触摸事件对象属性列表(继承 BaseEvent)
属性 类型 说明
touches Array 触摸事件,当前停留在屏幕中的触摸点信息的数组
changedTouches Array 触摸事件,当前变化的触摸点信息的数组
  • 事件对象属性说明

  • type
    通用事件类型

  • timeStamp
    该页面打开到触发事件所经过的毫秒数。

  • target
    触发事件的源组件

属性 类型 说明
id String 事件源组件的id
tagName String 当前组件的类型
dataset Object 事件源组件上由data-开头的自定义属性组成的集合
  • currentTarget
    事件绑定的当前组件
属性 类型 说明
id String 当前组件的id
tagName String 当前组件的类型
dataset Object 当前组件上由data-开头的自定义属性组成的集合
  • dataset

在组件中可以定义数据,这些数据将会通过事件传递给 SERVICE。书写方式:以data-开头,多个单词由连字符-链接,不能有大写(大写会自动转成小写)
data-element-type,最终在 event.target.dataset 中会将连字符转成驼峰 elementType
data-elementType,最终在 e.currentTarget.dataset.elementtype 大写会自动转成小写elementtype

  • 事件绑定

事件绑定的写法同组件的属性,以key、value的形式

  • key以bindcatch开头,然后跟上事件的类型,如bindtap, catchtouchstart
  • value是一个字符串,需要在对应的Page中定义同名的函数。不然当触发事件的时候会报错
<view bindtap="bindViewTap" data-field="name" data-text="aa"></view>
<view bind:tap="bindViewTap" data-field="name" data-text="aa"></view>

<view catch:tap="bindViewTap" data-field="name" data-text="aa"></view>
<view catchtap="bindViewTap" data-field="name" data-text="aa"></view>

bind与catch的区别

  • bind事件绑定不会阻止冒泡事件往上冒泡,简单来说,bind所绑定的事件对应会向上传递,让自己的父组件响应对应的事件。
  • catch事件会把对应的事件阻拦在自己这里,只有自己能够响应对应事件。
  • 事件的使用
<!--index.wxml-->
<view bindtap="bindViewTap" data-field="name" data-text="aa"></view>

// index.js
Page({
  // 事件处理函数
  bindViewTap(e) {
    var field= e.currentTarget.dataset.field;
    var aa= e.currentTarget.dataset.text;
  },
})
  • 事件参数
  • 使用:dataset
  • 注意:事件携带参数 dataset使用的时候 ,数据名尽量用小写,不要使用驼峰
<!--index.wxml-->
<view bindtap="bindViewTap" data-element-type="name" data-elementType="aa"></view>

// index.js
Page({
  // 事件处理函数
  bindViewTap(e) {
  // 获取时候  data-element-type  =  e.currentTarget.dataset.elementType 
  // 获取时候  data-elementType=  e.currentTarget.dataset.elementtype
  },
})
  • 使用wxs响应事件

支持使用 WXS 函数绑定事件,WXS函数接受2个参数:

  • event,在原有的 event 的基础上加了event.instance对象,
  • ownerInstance,和event.instance一样是一个ComponentDescriptor对象

在组件中绑定和注册事件处理的 WXS 函数

<!-- text.wxml -->
<wxs module="test" src="./test.wxs"></wxs>

<!-- 绑定wxs中函数 -->
<view id="tapTest" data-hi="Weixin" bindtap="{{test.tapName}}"> Click me! </view>

<!-- prop 属性改变的时候调用 propObserver -->
<view change:prop="{{test.propObserver}}" prop="{{propValue}}" class="movable"></view>

test.wxs文件实现 tapName 函数

// test.wxs
module.exports = {
    tapName: function(event, ownerInstance) {
      var hi= e.currentTarget.dataset.hi;
    },
    // 监听prop属性变化
    propObserver: function(newValue, oldValue, ownerInstance, instance) {
        console.log('prop observer', newValue, oldValue)
    }
}


  • 3.4.5 App.js中全局变量使用

可在App.js中定义全局变量

  • 定义
// app.js
App({
  onLaunch() { },
  globalData: {
    userInfo: null,
    dataList:[]
  }
})
  • 使用
//获取应用实例
const app = getApp();

Page({
  /**
   * 页面的初始数据
   */
  data: {
    // 图片链接
    img_server_url: app.globalData.img_server_url,
  },
  /* 修改全局变量 */
  updateRecord(data){
    //保存全局数据
    app.globalData.dataList= data;
    // 注意,修改后,此页面如果又用到了,重新获取app,不然值不会变。
    var app = getApp();
  },


  • 3.4.6 模块化

可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过module.exports或者 exports 才能对外暴露接口。

  • 定义公用变量 base.js
const accountInfo = wx.getAccountInfoSync();
let webViewSrc = 'http://cBus';
let pathWebViewSrc = 'https://***/index';
let userSubscribeUrl = 'https://i***e/app/user';
let SogoEnvVersion = 'trial'; //跳转到体验版
// let SogoEnvVersion = "release"; //跳转到生产版本
if (accountInfo.miniProgram.envVersion === 'trial') {
    webViewSrc = 'https://****tcBus';
    pathWebViewSrc = 'https://****ndex';
    userSubscribeUrl = 'https://****/user';
} else if (accountInfo.miniProgram.envVersion === 'release') {
    webViewSrc = 'https://***/ftcBus';
    pathWebViewSrc = 'https:/***/#/index';
    maasBaseUrl = 'https://***/entry';
    userSubscribeUrl = 'https://***/app/user';
}
module.exports = {
    webViewSrc,
    pathWebViewSrc,
    maasBaseUrl,
    SogoEnvVersion,
    userSubscribeUrl,
};

使用

import { maasBaseUrl, SogoEnvVersion } from "/utils/base.js"
Page({
  onLoad() {
    let ceshi = maasBaseUrl
    ...
  }
})
  • 定义公用函数 methods.js
/***
 * 转换距离 转换成相应的展示单位
 *  */
function computedDistance(distance) {
    if (distance > 1000) {
        return (distance / 1000) + 'km'
    } else {
        return distance + '米'
    }
};
/**
 * 判断用户滑动
 * 上滑还是下滑
 */
function getTouchData(endX, endY, startX, startY) {
    let turn = "";
    if (endY - startY > 50 && Math.abs(endX - startX) < 50) { //下滑
        turn = "bottom";
    } else if (endY - startY < -50 && Math.abs(endX - startX) < 50) { //上滑
        turn = "top";
    }
    return turn;
};
module.exports = {
    computedDistance,
    getTouchData
}

使用

import { computedDistance, getTouchData } from "/utils/methods.js"
Page({
  onLoad() {
    let ceshi = computedDistance('')
  }
})


  • 3.4.7 封装 wx-request.js
function tansParams(obj){
  var  str = "";
  for(var k in obj){
    str+=k+"="+obj[k]+"&";
  }
  //移除最后一个&
  return str.slice(0,-1);
}
function wxRequest(option){
  var url = option.url;
  // 选项里面有params(get传入的参数)
  if(option.params){
    // 如果有参数,把参数转换为url编码形式加入
    url+="?"+tansParams(option.params);
  }
  // 02 可以添加请求头
  var  header =  { };
  var contentType = option.contentType || 'form';
  header ['Content-Type'] = {
     form: 'application/x-www-form-urlencoded',
     json: 'application/json',
  }[contentType];
  header = {
    header,
    ...option.header
  }
  header.Authorization ="Bearer "+wx.getStorageSync('token');
  // 添加加载提示
  if(option.loading){
    wx.showToast({
      title: option.loading.title,
      icon:option.loading.icon,
    })
  }
  // 返回一个Promise
  return new Promise((resolve,reject)=>{
      wx.request({
        // 请求的地址如果一http开头直接用url不是http开头添加我们 baseUrL
        url: url,
        method:option.method||"GET",//请求的方法 默认get
        data:option.data, //post出入的参数
        header,
        success(res){
          // 请求成功
          resolve(res.data);
        },
        fail(err){
          // 04 对错误进行处理
          wx.showToast({title:"加载失败",icon:"none"})
          // 请求失败
          reject(err);
        },
        complete(){
          // 关闭加载提示
          wx.hideToast();
        }
      })
  })
} 
// 定义get简易方法
wxRequest.get= (url,config)=>{
  return request({url,method:"get",...config})
}
// 定义post简易方法
wxRequest.post= (url,data,config)=>{
  return request({url,method:"post",data,...config})
}
// 导入request
module.exports={
  wxRequest 
}

使用

import { wxRequest } from "/utils/wx-request.js"
Page({
  onLoad() {
    wxRequest({
            method: "POST",
            url: `${maasBaseUrl}/trp/api/v1/openResource/getRouteInfo`,
            data: routeNo
        }).then((res) => {
            if (res) {

            }
        })
  }
})


将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;在自定义组件的 js 文件中,需要使用 Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法。

组件的文件夹结构应和页面一样:.wxml .wxss .js .json

  • 定义组件
.json****************** 中配置这是一个组件
{
  "component": true
}

.wxml******************
<view class="inner">
  {{innerText}}
</view>
<slot></slot>

.wxss******************
.inner {
  color: red;
}

.js******************
Component({
  properties: {
    // 这里定义了 innerText 属性,属性值可以在组件使用时指定
    innerText: {
      type: String,
      value: 'default value',
    }
  },
  data: {
    // 这里是一些组件内部数据
    someData: {}
  },
  methods: {
    // 这里是一个自定义方法
    customMethod: function(){}
  }
})

  • 使用组件
// index.json 中引入组件
{
  "usingComponents": {
    "component-tag-name": "path/to/the/custom/component"
  }
}
// index.wxml 中使用组件
<view>
  <!-- 以下是对一个自定义组件的引用 -->
  <component-tag-name inner-text="Some text">
    <view>11111</view>
  </component-tag-name>
</view>
  • 开启多插槽模式(自定义组件默认是单插槽)
.js*********
Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多 slot 支持
  },
  properties: { /* ... */ },
  methods: { /* ... */ }
})

.wxml**********
<!-- 组件模板 -->
<view class="wrapper">
  <slot name="before"></slot>
  <view>这里是组件的内部细节</view>
  <slot name="after"></slot>
</view>

index.wxml 使用*********
<view>
  <component-tag-name>
    <!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
    <view slot="before">这里是插入到组件slot name="before"中的内容</view>
    <!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
    <view slot="after">这里是插入到组件slot name="after"中的内容</view>
  </component-tag-name>
</view>
  • 组件样式
    默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响,但是,可以配置页面和组件之间样式是否互相影响。

Component({}) 对象配置 options中有个属性styleIsolation:

  • isolated 表示启用样式隔离,互不影响。
  • apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
  • shared 表示页面wxss样式和组件wxss样式 相互影响。
.js*********
Component({
  options: {
    styleIsolation: 'isolated'
  }
})
  • 数据传输
    可以再组件properties 定义接收参数
Component({
  properties: {
    name: {
      type: 'String'
    },
    type: {
      type: 'String'
    },
    index:{
      type:'Number'
    }
  }
)}

<component-nav index="{{index}}" type="person" name="点击编辑【个人特征】{{index+1}}"/>
  • 事件沟通

自定义组件触发事件时,需要使用 triggerEvent 方法,接收参数参数:指定事件名、detail对象、事件选项;

触发事件的选项包括:

选项名 类型 是否必填 默认值 描述
bubbles Boolean false 事件是否冒泡
composed Boolean false 事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部
capturePhase Boolean false 事件是否拥有捕获阶段

代码示例:

组件**********************
<view>
  <!-- 定义事件 -->
  <button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
  <slot></slot>
</view>
Component({
  methods: {
    onTap: function(){
      // detail对象,提供给事件监听函数 传输数据
      var myEventDetail = {} 
      // 触发事件的选项
      var myEventOption = {
      
      } 
      // 组件通信
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }
})

使用**********************
<component-nav bindmyevent="onMyEvent"></component-nav>
Page({
  onMyEvent: function(e){
    e.detail // 自定义组件触发事件时提供的 detail 对象
  }
}

  • 获取组件实例

可在父组件里调用 this.selectComponent ,获取子组件的实例对象,调用时需要传入一个匹配选择器 selector。
如:this.selectComponent(".my-component"),父组件将会获取 class 为 my-component 的子组件实例对象,即子组件的 this 。

// .wxml***********
<component-nav class="component-nav"/>

// .js***********
Page({
  data: {},
  getChildComponent: function () {
    const child = this.selectComponent('.my-component');
    console.log(child)
  }
})
  • 示例创建自定义组件Nav

nav.json

{
  "component": true
}

nav.wxml

<view class="nav-item" bindtap="routeToFamily">
  <image src='{{img_server_url}}/ic_status_{{imgName}}.png' mode="aspectFit"></image>
  <view class="name">{{name}}</view>

  <!-- 定义事件 -->
  <button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>

  <slot name="before"></slot>
  <slot name="after"></slot>
</view>

nav.wxss

.nav-item{
  width:100%;
  height:70rpx;
  display: flex;
  flex-direction: row;
  align-items: center;
}
...

nav.js

//获取应用实例
const app = getApp();
Component({
  options: {
    // 在组件定义时的选项中启用多 slot 支持
    multipleSlots: true, 
    // isolated 表示启用样式隔离
    // apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
    // shared 表示页面 wxss 和 组件wxss 相互影响
    styleIsolation: 'isolated'
  },
  // 接收参数
  properties: {
    name: {
      type: 'String'
    },
    type: {
      type: 'String'
    },
    index:{
      type:'Number'
    }
  }, 
  data: {
    img_server_url: app.globalData.img_server_url,
    imgName:0,
    setIcon:false
  },
  pageLifetimes: {
    // 页面被展示
    show: function () {
      this.setData({
        setIcon:true
      });
      this.setIcon();
    }
  },
  ready(){

  },
  methods: {
    onTap: function(){
      var myEventDetail = {} // detail对象,提供给事件监听函数
      var myEventOption = {} // 触发事件的选项
      // 组件通信
      this.triggerEvent('myevent', myEventDetail, myEventOption)
      // 出发事件时,可传入配置
       // { bubbles:事件是否冒泡,composed: 事件是否可以穿越组件边界,为 false 时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部,capturePhase:事件是否拥有捕获阶段}
      this.triggerEvent('myevent', {}, { bubbles: true, composed: true }) 
    },
    setIcon:function(){

    }
    ...
  }
})
  • 在index页面中使用自定义组件Nav
// index.json
{
  "navigationBarTitleText": "样本",
  "navigationStyle": "custom",
  "usingComponents": {
    "component-nav": "../../component/nav/nav",
    "nav-bar": "../../component/navbar/index"
  }
}
// index.wxml
 <component-nav class="component-nav" bindmyevent="onMyEvent" type="family" name="点击编辑【户特征】">
    <!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
    <view slot="before">这里是插入到组件slot name="before"中的内容</view>
    <!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
    <view slot="after">这里是插入到组件slot name="after"中的内容</view>
</component-nav>

// index.js
Page({
   // 这样可以获取到子组件
  getChildComponent: function () {
    // 调用组件时候,给起一个 id、class 都可以
    const child = this.selectComponent('.component-nav'); // #
    console.log(child)
  }
  onMyEvent: function(e){
    // 自定义组件触发事件时提供的 detail 对象 数据
    e.detail 
  }
})


  • 3.4.9 页面跳转
  • 使用API跳转
路由方式 功能描述 路由前页面 路由后页面
navigateTo 打开新页面 onHide onLoad, onShow
redirectTo 页面重定向 onUnload onLoad, onShow
navigateBack 页面返回 onUnload onShow
switchTab Tab 切换 onHide onUnload.. onLoad B.onShow..
reLaunch 重启动 onUnload onLoad, onShow

共有 switchTab reLaunch redirectTo navigateTo navigateBack 五个方法,可以通过 this.pageRouterthis.routerwx对象 wxNavAction , 获得当前页面或自定义组件的路由器对象,进行跳转,功能相同;但有区别。

注意:

  • navigateTo,redirectTo只能打开非 tabBar 页面。
  • switchTab 只能打开 tabBar 页面。
  • reLaunch 可以打开任意页面。
  • 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
  • 调用页面路由带的参数可以在目标页面的onLoad中获取。
  • 非tabba页面跳转 navigateTo、redirectTo、navigateBack等
// 保留当前页面,跳转到应用内的某个页面。
wx.navigateTo({
  url: '/pages/calculator/calculator',
})
this.pageRouter.navigateTo({
  url: '/pages/calculator/calculator',
})
this.router.navigateTo({
  url: '/pages/calculator/calculator',
})

// 关闭当前页面,跳转到应用内的某个页面。
wx.redirectTo({
  url: '/pages/calculator/calculatort?id=1'
})
this.pageRouter.redirectTo({
  url: '/pages/calculator/calculatort?id=1'
})

// 关闭当前页面,返回上一页面或多级页面 参数是后退数
wx.navigateBack({
  delta: 1 // 2 3
})
...
  • tabbar页面跳转 wx.switchTab
wx.switchTab({
  url: '/pages/calculator/calculator',
})
this.pageRouter.switchTab({
  url: '/pages/calculator/calculator',
})

唯一的区别是,页面路由器中的方法调用时,相对路径永远相对于 this 指代的页面或自定义组件,比wx.navigateTo等方法稳定。
在使用相对路径跳转的时候

  • 页面 index/index 的 js 代码如下所示。如果此时已经跳转到了一个新页面 pack/index ,然后才调用到上面的 wxNavAction 方法,跳转的新页面路径将是 pack/new-page ;而如果调用的是 routerNavAction 方法,跳转的新页面路径仍然是 index/new-page。
// com/index.js
Page({
  wxNavAction: function () {
    wx.navigateTo({
      url: './new-page'
    })
  },
  routerNavAction: function () {
    // this.pageRouter 
    this.pageRouter.navigateTo({
      url: './new-page'
    })
  }
})
  • this.pageRouter 和 this.router区别
    this.pageRouter 和 this.router 在页面中将获得同样的页面路由器对象。
    但如果在自定义组件中调用, this.pageRouter 将相对于自定义组件所在的页面来进行路由跳转,而 this.router 相对于自定义组件自身的路径。
// components/ceshi/index.js
Component({
    /**
     * 组件的方法列表
     */
    methods: {
        goto(){
            //路径:index/logs/logs
            // wx.navigateTo({
            //     url: './logs/logs'
            // })
            //路径:index/logs/logs
            // this.pageRouter.navigateTo({
            //     url: './logs/logs'
            // })
            //路径:ceshi/logs/logs
            this.router.navigateTo({
                url: './logs/logs'
            })
        }
    }
})

// 使用组件
<!--index.wxml-->
<view class="container">
    <ceshi/>
    <button bindtap="bindViewTap">2222</button>
<!-- 引入 -->
</view>
  • 使用组件标签navigator 跳转
    navigator 页面链接
属性名 类型 默认值 说明
target String self 在哪个目标上发生跳转,默认当前小程序,可选值self/miniProgram
url String 应用内的跳转链接
open-type String navigate 跳转方式
delta Number 当 open-type 为 'navigateBack' 时有效,表示回退的层数
app-id String 当target="miniProgram"时有效,要打开的小程序 appId
path String 当target="miniProgram"时有效,打开的页面路径,如果为空则打开首页
extra-data Object 当target="miniProgram"时有效,需要传递给目标小程序的数据,目标小程序可在 App.onLaunch()App.onShow() 中获取到这份数据。
version version release 当target="miniProgram"时有效,要打开的小程序版本,有效值 develop(开发版),trial(体验版),release(正式版),仅在当前小程序为开发版或体验版时此参数有效;如果当前小程序是正式版,则打开的小程序必定是正式版。
hover-class String navigator-hover 指定点击时的样式类,当hover-class="none"时,没有点击态效果
hover-stop-propagation Boolean false 指定是否阻止本节点的祖先节点出现点击态
hover-start-time Number 50 按住后多久出现点击态,单位毫秒
hover-stay-time Number 600 手指松开后点击态保留时间,单位毫秒
bindsuccess String 当target="miniProgram"时有效,跳转小程序成功
bindfail String 当target="miniProgram"时有效,跳转小程序失败
bindcomplete String 当target="miniProgram"时有效,跳转小程序完成

open-type 有效值:

说明 最低版本
navigate 对应wx.navigateTo的功能
redirect 对应wx.redirectTo的功能
switchTab 对应wx.switchTab的功能
reLaunch 对应wx.reLaunch的功能 1.1.0
navigateBack 对应wx.navigateBack的功能 1.1.0
exit 退出小程序,target="miniProgram"时生效 2.1.0

注:navigator-hover默认为{background-color: rgba(0, 0, 0, 0.1); opacity: 0.7;}, <navigator/>的子节点背景色应为透明色

<view class="btn-area">
  <navigator url="/page/navigate/navigate?title=navigate" hover-class="navigator-hover">跳转到新页面</navigator>
  <navigator url="../../redirect/redirect/redirect?title=redirect" open-type="redirect" hover-class="other-navigator-hover">在当前页打开</navigator>
  <navigator url="/page/index/index" open-type="switchTab" hover-class="other-navigator-hover">切换 Tab</navigator>
  <navigator target="miniProgram" open-type="navigate" app-id="" path="" extra-data="" version="release">打开绑定的小程序</navigator>
</view>
  • 页面跳转传参
    传输
    直接放到页面路径后既可。示例:
  // 查看地图分布
  clickAllParkMap(){
    var parkId=this.data.parkData[0].parkId;
    wx.navigateTo({
      url: "../park-map/park-map?inputValue="+this.data.inputValue+'&parkId='+parkId
    });
  },
  // 点击单个
  clickParkMap(e){
    var index = e.currentTarget.dataset.text;
    var parkId=this.data.parkData[index].parkId;
    var parkName = this.data.parkData[index].parkName;
    wx.navigateTo({
      url: "../park-map/park-map?inputValue="+parkName+'&parkId='+parkId
    });
  },

获取
在页面的onLoad函数,接收参数 options 中获取,

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var parkId=options.parkId || null;
    var parkName=options.parkId || null;
  },


  • 3.4.10 提示、加载
  • wx.showToast 显示消息提示框
  • wx.hideToast 隐藏消息提示框
  • wx.showModal 显示模态对话框
  • wx.showLoading 显示 loading 提示框
  • wx.hideLoading 关闭 loading 提示框
  • wx.showActionSheet 显示操作菜单
  • wx.showToast(option) 显示消息提示框
参数 类型 必填 说明
title String 提示的内容
icon String 图标,有效值"success"、"error" 、"loading" 、"none"
image String 自定义图标的本地路径,image 的优先级高于 icon
duration Number 提示的延迟时间,单位毫秒,默认:1500
mask Boolean 是否显示透明蒙层,防止触摸穿透,默认:false
success Function 接口调用成功的回调函数
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)
wx.showToast({
  title: '成功',
  icon: 'success', 
  duration: 2000
})

wx.hideToast()
显示消息提示框.png
  • wx.showModal(option) 显示模态对话框
参数 类型 必填 说明
title String 提示的标题
content String 提示的内容
showCancel Boolean 是否显示取消按钮,默认为 true
cancelText String 取消按钮的文字,默认为"取消",最多 4 个字符
cancelColor HexColor 取消按钮的文字颜色,默认为"#000000"
confirmText String 确定按钮的文字,默认为"确定",最多 4 个字符
confirmColor HexColor 确定按钮的文字颜色,默认为"#3CC51F"
success Function 接口调用成功的回调函数
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)

succes返回参数说明:

参数 类型 说明
confirm Boolean 为 true 时,表示用户点击了确定按钮
cancel Boolean 为 true 时,表示用户点击了取消(用于 Android 系统区分点击蒙层关闭还是点击取消按钮关闭)
wx.showModal({
  title: '提示',
  content: '这是一个模态弹窗',
  success (res) {
    if (res.confirm) {
      console.log('用户点击确定')
    } else if (res.cancel) {
      console.log('用户点击取消')
    }
  }
})
显示模态对话框.png
  • wx.showActionSheet(option) 显示操作菜单
参数 类型 必填 说明
itemList String Array 按钮的文字数组,数组长度最大为6个
itemColor HexColor 否 按钮的文字颜色,默认为"#000000"
success Function 接口调用成功的回调函数,详见返回参数说明
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)

success返回参数说明:

参数 类型 说明
tapIndex Number 用户点击的按钮,从上到下的顺序,从0开始
wx.showActionSheet({
  itemList: ['A', 'B', 'C'],
  success (res) {
    console.log(res.tapIndex)
  },
  fail (res) {
    console.log(res.errMsg)
  }
})
显示操作菜单.png

注意

  • wx.showLoadingwx.showToast同时只能显示一个
  • wx.showToast 应与 wx.hideToast配对使用


  • 3.4.11 自定义导航栏
    使用page.json中配置:navigationStyle 。 详情可以看我另外一片文章 自定义页面导航栏
属性 类型 默认值 描述
navigationStyle string default 导航栏样式,配置值:default默认、custom自定义,只保留右上角胶囊按钮
usingComponents Object 无 页面自定义组件配置
  • 在对应页面的json中开启自定义顶部状态栏,且引入自定义的状态栏组件。
  "navigationStyle": "custom",
  "usingComponents": {
    "nav-bar": "../../component/navbar/index"
  }
  • 自定义组件navbar
  • 在 app.js中获取 手机的状态栏高度以及字体大小。wx.getSystemInfo()
onLaunch: function () {
  //获取手机导航栏高度
    wx.getSystemInfo({
      success: res => {
        var isIos = res.system.indexOf('iOS') > -1;
        this.globalData.statusHeight = res.statusBarHeight;
        this.globalData.navHeight = isIos ? 44 : 48;
        this.globalData.fontSize = res.fontSizeSetting;
        //设置低版本不显示自定义导航栏
        if (res.SDKVersion && res.SDKVersion.split('.')[0] * 1 <= 2 && res.SDKVersion.split('.')[1] * 1 < 5){
          this.globalData.navHeightHidden=true;
        }
      },
      fail(err) {
        console.log(err);
      }
    })
}
globalData: {
    //自定义导航组件高度
    navHeightHidden:false,
    statusHeight:null,
    navHeight:null,
    fontSize:null,
}
  • navbar.wxml
  <!-- 如果版本低于2.5后,不显示自定义状态栏 -->
<block wx:if="{{navHeightHidden}}">
  <view></view>
</block>
<block wx:else>
  <view style="height:{{statusHeight+navHeight}}px" hidden='{{header.hiddenBlock}}'></view>
  <view class='topbar' style="background:{{header.headerbg}}">
    <view class='status' style="height:{{statusHeight}}px"></view>
    <view class='navbar' style="height:{{navHeight}}px">
      <block wx:if="{{header.slot}}">
        <slot></slot>
      </block>
      <block wx:else>
        <view class='navbar_home' wx:if="{{header.homeCapsule}}" style="background:{{header.capsulebg}};border:{{header.capsuleborder}}">
          <image src='../../images/black_back.png' bindtap='backClick' style="border-right:{{header.capsulesep}}"></image>
          <image src='../../images/home_black.png' bindtap='homeClick'></image>
        </view>
        <view class='navbar_back' bindtap='backClick' wx:else>
          <image src='../../images/black_back.png'></image>
        </view>
        <view class='navbar_title' style="height:{{navHeight}}px">
          <view style="color:{{header.fontColor}};font-size:{{fontSize}}px">{{header.title}}</view>
        </view>
      </block>
    </view>
  </view>
</block>
  • navbar.wxss
.topbar {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  z-index: 9999;
}
.status {
  width: 100%;
}
...
  • navbar.js
    编写业务员逻辑,我的是点击左上角返回按钮的事件,弹窗提示要不要返回
var app = getApp();
Component({
  properties: {
    header: {
      type: Object,
      value: {
        homeCapsule: false,
        headerbg: "#fff",
        title: "",
        fontColor: "#000",
        fontSize: '16',
        hiddenBlock: false,
        capsulebg: 'rgba(0,0,0,0.2)',
        capsuleborder: '1px solid rgba(0, 0, 0, 0.1)',
        capsulesep: '1px solid rgba(255,255,255,0.2)',
        slot: false
      }
    },
    customBackReturn: {
      type: Boolean,
      value: false
    }
  },
  data:{
    statusHeight: app.globalData.statusHeight,
    navHeight: app.globalData.navHeight,
    fontSize: app.globalData.fontSize,
    navHeightHidden: app.globalData.navHeightHidden
  },
  methods: {
    // 定义点击左上角返回按钮的函数 
    backClick() {
      var me=this;
      wx.showModal({
        title: '提示',
        content: '如有改动,请确认是否已点击【保存】',
        success(res) {
          if (res.confirm) {
            if (me.data.customBackReturn) {
              me.triggerEvent("customBackReturn")
            } else {
              if (getCurrentPages().length == 1) {
                wx.switchTab({
                  url: '/pages/index/index',
                })
              } else {
                wx.navigateBack({
                  delta: 1
                })
              }
            }
          } else if (res.cancel) {
            
          }
        }
      })
      
    },
    homeClick() {
      wx.switchTab({
        url: '/pages/index/index',
      })
    }
  }
})
  • 组件的json index.json
{
  "component": true
}
  • 使用组件
  • 在对应页面的json中开启自定义顶部状态栏,且引入自定义的状态栏组件。
  "navigationStyle": "custom",
  "usingComponents": {
    "nav-bar": "../../component/navbar/index"
  }
  • 在对应页面的js中写好定义的组件状态和标题名
//自定义顶部  参数直接能看懂
    nvabarData: {
      homeCapsule: false, 
      title: '户特征',
      fontColor: "white",
      fontSize: '26rpx',
      headerbg: '#04aceb',
      hiddenBlock: false,
      slot: false
    },
    // 整个导航栏高度
    navHeight: app.globalData.navHeight + app.globalData.statusHeight,
    // 是否显示自定义导航栏(为低版本)
    navHeightHidden: app.globalData.navHeightHidden,
  • 在index 中使用自定义组件
<!-- 自定义顶部 -->
<nav-bar header='{{nvabarData}}'></nav-bar>

// 我的页面用的是100% 高度的布局, 所有要减去这个状态栏的高度
<view class="container" style="height: calc( 100% - {{navHeightHidden?0:navHeight}}px );"></view>
image.png


四、常用功能

4.1 常用小程序api

  • 4.1.1 数据缓存 官方API地址
  • wx.setStorage(option)
    将数据存储在本地缓存中指定的key中,会覆盖掉原来该key对应的内容,这是一个异步接口。
    设置setStorage、获取getStorage、删除removeStorage
    OBJECT参数说明

参数 类型 必填 说明
key String 本地缓存中的指定的 key
data Object/String 需要存储的内容
success Function 接口调用成功的回调函数
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)
Page({
  data: {
    logs: []
  },
  onLoad() {
    // 设置
   wx.setStorage({
        key:"key11",
        data:"value"
    })
    // 获取
    wx.getStorage({
        key: 'key11',
        success (res) {
            // 直接就是对象
            console.log(res.data)
        }
    })
   // 批量读取 数组
    wx.batchGetStorage({
      keyList: ['key11'],
      success (res) {
        console.log(res) 
      }
    })
    // 删除
     wx.removeStorage({
          key: 'key',
          success (res) {
              console.log(res)
          }
      })
  }
})
  • wx.setStorageSync(option)
    将data存储在本地缓存中指定的key中,会覆盖掉原来该key对应的内容,这是一个同步接口。
    设置setStorageSync、获取getStorageSync、删除removeStorageSync
    OBJECT参数说明
参数 类型 必填 说明
key String 本地缓存中的指定的key
data Object/String 需要存储的内容
Page({
    data: {
        regionData:null
    },
    onLoad() {
        // 设置
        wx.setStorageSync('regionData', {a:1,b:2});
        // 获取 直接就是对象
        var regionData = wx.getStorageSync('regionData') || '';
        // 删除
        wx.removeStorageSync('regionData');
    }
})
  • wx.batchSetStorageSync(option) 批量存储
    Array.<Object> kvList,将数据批量存储在本地缓存中指定的 key 中,单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB。这是一个同步接口。
    等同于多个setStorageSync ,但是对于多个 key 的读取, 批量读取在性能上优于多次 getStorageSync 读取
    OBJECT参数说明 Array.<Object> kvList
参数 类型 必填 说明
key String 本地缓存中的指定的key
data Object/String 需要存储的内容
Page({
    data: {
        regionData:null
    },
    onLoad() {
        // 设置
        wx.batchSetStorageSync([
            {key: 'key1', value: '1'},
            {key: 'key2', value: {a:1,b:2} }
        ])
        // 获取
        var valueList = wx.batchGetStorageSync(['key1','key2'])
        // ["1", "2"]
        // 删除
        // 使用removeStorageSync 单个删除;
    }
})

以上三类存储API,注意事项:
1:存储同样的key,会覆盖掉原来该 key 对应的内容。
2:除非用户主动删除或因存储空间原因被系统清理,否则数据都一直可用。



  • 4.1.2 微信小程序画布 canvas

微信小程序标签组件:canvas

属性 类型 默认值 必填 说明 最低版本
type string 指定 canvas 类型,支持 2d (2.9.0) 和 webgl (2.7.0) 2.7.0
canvas-id string canvas 组件的唯一标识符,若指定了 type 则无需再指定该属性 1.0.0
disable-scroll boolean false 当在 canvas 中移动时且有绑定手势事件时,禁止屏幕滚动以及下拉刷新 1.0.0
bindtouchstart eventhandle 手指触摸动作开始 1.0.0
bindtouchmove eventhandle 手指触摸后移动 1.0.0
bindtouchend eventhandle 手指触摸动作结束 1.0.0
bindtouchcancel eventhandle 手指触摸动作被打断,如来电提醒,弹窗 1.0.0
bindlongtap eventhandle 手指长按 500ms 之后触发,触发了长按事件后进行移动不会触发屏幕的滚动 1.0.0
binderror eventhandle 当发生错误时触发 error 事件,detail = {errMsg} 1.0.0

注意事项:

  1. canvas 标签默认宽度300px、高度150px
  2. 同一页面中的 canvas-id 不可重复,如果使用一个已经出现过的 canvas-id,该 canvas 标签对应的画布将被隐藏并不再正常工作
  3. 请注意原生组件使用限制
  4. 开发者工具中默认关闭了 GPU 硬件加速,可在开发者工具的设置中开启“硬件加速”提高 WebGL 的渲染性能
  5. WebGL 支持通过 getContext('webgl', { alpha: true }) 获取透明背景的画布
  6. Canvas 2D(新接口)需要显式设置画布宽高 (默认为 300x150)
  7. 避免设置过大的宽高,在安卓下会有crash的问题
  • Canvas 2D 示例代码
<!-- canvas.wxml -->
  <canvas type="2d" id="myCanvas"></canvas>

// canvas.js
Page({
  onReady() {
    const query = wx.createSelectorQuery()
    query.select('#myCanvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')

        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctx.scale(dpr, dpr)

        ctx.fillRect(0, 0, 100, 100)
      })
  }
})
  • WebGL 示例代码
 <!-- canvas.wxml -->
  <canvas type="webgl" id="myCanvas"></canvas>

// canvas.js
Page({
  onReady() {
    const query = wx.createSelectorQuery()
    query.select('#myCanvas').node().exec((res) => {
      const canvas = res[0].node
      const gl = canvas.getContext('webgl')
      gl.clearColor(1, 0, 1, 1)
      gl.clear(gl.COLOR_BUFFER_BIT)
    })
  }
})
  • 示例
Page({
    data: {

    },
    
  // 画背景
  drawProgressbg: function () {
    // 使用 旧api绘制 + 新api 自动适配圆圈大小
    const query = wx.createSelectorQuery();
    query.select('#canvasProgressbg')
      .fields({ node: true, size: true })
      .exec((res) => {
        // 获取 px -> rpx 比例
        // const dpr = wx.getSystemInfoSync().pixelRatio;
        var width = res[0].width;
        var height = res[0].height;
        var ctx = wx.createCanvasContext('canvasProgressbg', this)
        ctx.setLineWidth(4);// 设置圆环的宽度
        ctx.setStrokeStyle('#e2e0e0'); // 设置圆环的颜色
        ctx.setLineCap('round') // 设置圆环端点的形状
        ctx.beginPath();//开始一个新的路径
        var radius = (height - 26) / 2;
        //设置圆的路径到当前路径
        ctx.arc(width / 2, height / 2, radius, 0, 2 * Math.PI, false);
        ctx.stroke();//对当前路径进行描边
        ctx.draw();
      })
  },
  // 画公交线路倒计时 参数: step=( 到站秒数 / (900/2) )    最大900s
  drawCircle: function (step) {
    // 使用 旧api绘制 + 新api 自动适配圆圈大小
    const query = wx.createSelectorQuery();
    query.select('#canvasProgress')
      .fields({ node: true, size: true })
      .exec((res) => {
        // 获取 px -> rpx 比例
        // const dpr = wx.getSystemInfoSync().pixelRatio;
        var width = res[0].width;
        var height = res[0].height;
        var ctx = wx.createCanvasContext('canvasProgress', this);
        // 设置渐变
        var gradient = ctx.createLinearGradient(200, 100, 100, 200);
        gradient.addColorStop("0", "#77d0dc");
        gradient.addColorStop("0.5", "#1db1c6");
        gradient.addColorStop("1.0", "#09b1c7");
        ctx.setLineWidth(6);
        ctx.setStrokeStyle(gradient);
        ctx.setLineCap('round')
        ctx.beginPath();
        var radius = (height - 30) / 2;
        // 参数step 为绘制的圆环周长,从0到2为一周 。 -Math.PI / 2 将起始角设在12点钟位置 ,结束角 通过改变 step 的值确定
        ctx.arc(width / 2, height / 2, radius, -Math.PI / 2, step * Math.PI - Math.PI / 2, false);
        ctx.stroke();

        // 画跟随的圆圈 内圆
        var e = step * Math.PI - Math.PI / 2;
        ctx.beginPath()
        let x, y, r1 = 8;
        // 通过三角函数计算x y 坐标
        x = radius * Math.cos(e) + width / 2;        
        y = radius * Math.sin(e) + width / 2;
        ctx.arc(x, y, r1, 0, 2 * Math.PI)
        ctx.fillStyle = 'rgba(29,177,198,1)';
        ctx.fill()
        ctx.closePath()
        // 外圆
        ctx.beginPath()
        let r2 = 15
        ctx.arc(x, y, r2, 0, 2 * Math.PI);
        ctx.fillStyle = 'rgba(29,177,198,0.5)'
        ctx.fill()
        ctx.closePath();
        ctx.draw();
      })
  },
})
image.png


  • 4.1.3 相机 wx.chooseImage

使用接口:wx.chooseImage(Object object)从本地相册选择图片或使用相机拍照。具体可看我另外一篇文章 微信小程序调用相机
参数

属性 类型 说明
width number 图像数据矩形的宽度
height number 图像数据矩形的高度
data ArrayBuffer 图像像素点数据,一维数组,每四项表示一个像素点的 rgba

返回值参数

属性 类型 默认值 必填
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

success 返回值 res

属性 类型 说明
tempThumbPath string 封面图片文件的临时路径 (本地路径)
tempVideoPath string 视频的文件的临时路径 (本地路径)
Page({
  data: {
    carWin_img_hidden:true, //展示照片的view是否隐藏
    carWin_img:'' //存放照片路径的
  },
//页面加载设置初始值 可以不要
  onReady(res){
    this.setData({
      carWin_img_hidden: true,
      carWin_img: ''
    });
  },
//点击事件
  clickCarWin(){
    var that = this;
    wx.chooseImage({
      count: 1,
      success: function (res) {
        // 无论用户是从相册选择还是直接用相机拍摄,路径都是在这里面
        var filePath = res.tempFilePaths[0];
        //将刚才选的照片/拍的 放到下面view视图中
        that.setData({
          carWin_img: filePath, //把照片路径存到变量中,
          carWin_img_hidden: false //让展示照片的view显示
        });
        // 这个是使用微信接口保存文件到数据库
        // wx.uploadFile({
        //   url: "",
        //   filePath: filePath,
        //   name: 'file',
        //   success: function (res) {

        //   }
        // })
      },
      fail: function (error) {
        console.error("调用本地相册文件时出错")
        console.warn(error)
      },
      complete: function () {

      }
    });
  }
})
image.png

image.png


  • 4.1.4 获取位置

获取用户位置信息,共需要使用以下三个api:

  • wx.getSetting 获取用户授权信息列表
  • wx.authorize 向用户发起授权请求
  • wx.getLocation 获取用户位置信息
  • wx.getSetting(option)
    获取用户的当前设置。*返回值中只会出现小程序已经向用户请求过的权限。

option 参数说明

属性 类型 默认值 说明
withSubscriptions Boolean false 是否同时获取用户订阅消息的订阅状态,默认不获取。
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

success 回调函数

属性 类型 说明
authSetting AuthSetting 用户授权结果
subscriptionsSetting SubscriptionsSetting 用户订阅消息设置,接口参数withSubscriptions值为true时才会返回。
miniprogramAuthSetting AuthSetting 在插件中调用时,当前宿主小程序的用户授权结果
wx.getSetting({
  success (res) {
    console.log(res.authSetting)
    // res.authSetting = {
    //   "scope.userInfo": true,
    //   "scope.userLocation": true
    // }
  }
})

option参数说明

属性 类型 必填 说明
scope string 需要获取权限的 scope
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
wx.getSetting({
  success(res) {
   // 查询用户是否授权位置信息
   if (!res.authSetting['scope.userLocation']) {
      // 调用位置授权
      wx.authorize({
        scope: 'scope.userLocation',
        success() { }
      })
    }
  }
})
  • wx.getLocation(option)
    获取当前的地理位置、速度。当用户离开小程序后,此接口无法调用;当用户点击“显示在聊天顶部”时,此接口可继续调用。

option参数说明

参数 类型 必填 说明
type String 默认为"wgs84"返回gps坐标,"gcj02"返回可用于wx.openLocation的坐标
success Function 接口调用成功的回调函数,返回内容详见返回参数说明。
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)

success返回参数说明

参数 说明
latitude 纬度,浮点数,范围为-90~90,负数表示南纬
longitude 经度,浮点数,范围为-180~180,负数表示西经
speed 速度,浮点数,单位m/s
accuracy 位置的精确度
altitude 高度,单位 m
verticalAccuracy 垂直精度,单位 m(Android 无法获取,返回 0)
horizontalAccuracy 水平精度,单位 m
wx.getLocation({
 type: 'wgs84',
 success (res) {
   const latitude = res.latitude
   const longitude = res.longitude
   const speed = res.speed
   const accuracy = res.accuracy
 }
})
  • 获取用户位置信息示例
  • 第一步:在app.json中申明
{
    "pages": [
        "pages/index/index"
    ],
    "window": {
        "backgroundTextStyle": "light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "Weixin",
        "navigationBarTextStyle": "black"
    },
    "permission": {
      "scope.userLocation": {
        "desc": "你的位置信息将用于小程序首页获取附近公交站点"
      }
    },
    "style": "v2",
    "sitemapLocation": "sitemap.json"
}
  • 第二步:提前让用户授权,示例在app.js中调用wx.getSetting、wx.authorize 弹窗让用户授权
// app.js
App({
  onLaunch() {
    // 位置授权
    wx.getSetting({
        success(res) {
          if (!res.authSetting['scope.userLocation']) {
            wx.authorize({
              scope: 'scope.userLocation',
              success() { }
            })
          }
        }
      })
  },
  globalData: {
    userInfo: null
  }
})

  • 第三步:在需要获取位置的地方,调用获取
<!--index.wxml-->
<view class="container">
    <map id="myMap" show-location />
<button type="primary" bindtap="getCenterLocation">获取位置</button>
<button type="primary" bindtap="moveToLocation">移动位置</button>
<button type="primary" bindtap="translateMarker">移动标注</button>
<button type="primary" bindtap="includePoints">缩放视野展示所有经纬度</button>
</view>
// map.js
Page({
    onReady: function (e) {
      // 使用 wx.createMapContext 获取 map 上下文
      this.mapCtx = wx.createMapContext('myMap')
    },
    getCenterLocation: function () {
      this.mapCtx.getCenterLocation({
        success: function(res){
          console.log(res.longitude)
          console.log(res.latitude)
        }
      })
    },
    moveToLocation: function () {
      this.mapCtx.moveToLocation()
    },
    translateMarker: function() {
      this.mapCtx.translateMarker({
        markerId: 0,
        autoRotate: true,
        duration: 1000,
        destination: {
          latitude:23.10229,
          longitude:113.3345211,
        },
        animationEnd() {
          console.log('animation end')
        }
      })
    },
    includePoints: function() {
      this.mapCtx.includePoints({
        padding: [10],
        points: [{
          latitude:23.10229,
          longitude:113.3345211,
        }, {
          latitude:23.00229,
          longitude:113.3345211,
        }]
      })
    }
  })
image.png

image.png


  • 4.1.5 屏幕操作
  • 设置屏幕亮度:wx.setScreenBrightness()
    参数值:value 0-1,越大越亮
if (wx.setScreenBrightness) {
      //设置屏幕亮度  参数值:0-1,越大越亮
      wx.setScreenBrightness({
        value: 0.6
      });
    } else {
      // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
      wx.showModal({
        title: '提示',
        content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
      })
    }
  • 获取屏幕亮度 wx.getScreenBrightness()
if (wx.getScreenBrightness) {
      //获取屏幕亮度 值:0-1,越大越亮
      success: function (res) {
        // res.value
      },
      fail: function () {
        //请求失败 
      }
    } else {
      // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
      wx.showModal({
        title: '提示',
        content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
      })
    }

以上两个方法可以配合使用,设置前记得先获取一下屏幕亮度,存起来,设置好亮度等不需要这么亮或用户退出程序时候,在给设置回去,这样用户体验好一些。
注:记得别忘记用户退出程序或者是某个界面时,恢复一下了亮度。

  • 设置屏幕常亮 wx.setKeepScreenOn
    参数值: true / false
if (wx.setScreenBrightness) {
      // 保持屏幕常亮 true / false
      wx.setKeepScreenOn({
        keepScreenOn: false
      });
    } else {
      // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
      wx.showModal({
        title: '提示',
        content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
      })
    }

注:记得别忘记用户退出程序或者是某个界面时,重新设置一下不常亮。



  • 4.1.6 扫码 wx.scanCode

调起客户端扫码界面进行扫码

option参数说明

属性 类型 默认值 说明
onlyFromCamera boolean false 是否只能从相机扫码,不允许从相册选择图片
scanType Array.<string> ['barCode', 'qrCode'] 扫码类型
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.scanType 的合法值

说明
barCode 一维码
qrCode 二维码
datamatrix Data Matrix 码
pdf417 PDF417 条码

success res

属性 类型 说明
result string 所扫码的内容
scanType string 所扫码的类型
charSet string 所扫码的字符集
path string 当所扫的码为当前小程序二维码时,会返回此字段,内容为二维码携带的 path
rawData string 原始数据,base64编码
// 允许从相机和相册扫码
wx.scanCode({
  success (res) {
    console.log(res)
  }
})

// 只允许从相机扫码
wx.scanCode({
  onlyFromCamera: true,
  success (res) {
    console.log(res)
  }
})


4.2 第三方插件使用

微信官方及第三方等提供了很多优秀的小程序页面插件,如:腾讯位置服务地图选点、腾讯位置导航等,使用方式相同,均是无缝跳转到插件小程序页面

  • 在微信公众平台中配置插件
    “微信小程序官方后台-设置-第三方服务-插件管理” 里点击 “添加插件”,如:搜索 “腾讯位置服务地图选点” 申请,审核通过后,小程序开发者可在小程序内使用该插件。
image.png
  • 引入插件包
    点击插件详情,既可看到插件APPid
image.png
  • 在app.json中配置使用插件
{
    "pages": [
        "pages/index/index",
        "pages/logs/logs",
        "components/ceshi"
    ],
    "window": {
        "backgroundTextStyle": "light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "Weixin",
        "navigationBarTextStyle": "black"
    },
    "permission": {
      "scope.userLocation": {
        "desc": "你的位置信息将用于小程序首页获取附近公交站点"
      }
    },
    "plugins": {
        "routePlan": {
            "version": "1.0.5",
            "provider": "wx76a9a06e5b4e693e"
        }
    },
    "style": "v2",
    "sitemapLocation": "sitemap.json"
} 
  • 设置定位授权
    地图选点插件需要小程序提供定位授权才能够正常使用定位功能:
// app.json
    {
    "permission": {
        "scope.userLocation": {
        "desc": "你的位置信息将用于小程序定位"
        }
    }
}
  • 使用插件
    插件页面调用示例:
const key = ''; //使用在腾讯位置服务申请的key
const referer = ''; //调用插件的app的名称
// 初始位置的经纬度,如果不传 默认当前位置
const location = JSON.stringify({
  latitude: 39.89631551,
  longitude: 116.323459711
});
const category = '生活服务,娱乐休闲';
 
wx.navigateTo({
  url: 'plugin://chooseLocation/index?key=' + key + '&referer=' + referer + '&location=' + location + '&category' + category
});
  • 插件返回数据
//地图返回 在页面的 onShow中 获取数据返回。
        const location = chooseLocation.getLocation();
        // 返回的数据放在这个对象里面
        if (location) {
          allData.address_name = location.name;
          allData.address = location.address;
          allData.address_poi = location.latitude + ',' + location.longitude;
        }

效果如下

image.png

image.png

image.png


4.3 微信扫码快捷打开小程序页面

微信公众平台开放扫描普通链接二维码跳转小程序能力。

普通链接二维码,是指开发者使用工具对网页链接进行编码后生成的二维码。
线下商户可不需更换线下二维码,在小程序后台完成配置后,即可在用户扫描普通链接二维码时打开小程序,使用小程序的功能。
对于普通链接二维码,目前支持使用微信“扫一扫”或微信内长按识别二维码跳转小程序。

  • 登录小程序后台
    进入“设置-开发设置-扫普通链接二维码打开小程序”,开启功能后即可配置二维码规则。
image.png
  • 配置规则
  • 二维码规则
    二维码规则的域名须通过ICP备案的验证。
    支持http、https、ftp开头的链接,一个小程序帐号可配置不多于10个二维码前缀规则。
  • 前缀占用规则
    可选择是否占用符合二维码匹配规则的所有子规则。如选择占用,则其他帐号不可申请使用满足该前缀匹配规则的其他子规则。
    如:若开发者A配置二维码规则:http://aaa/mp?id=123,并选择“占用所有子规则“,其他开发者将不可以配置满足前缀匹配的子规则

下载随机校验文件,并将文件上传至服务器指定位置的目录下(你填写的这个链接,加上这个校验文件名称,必须能访问到,如:http://aaa/mp/rOO4daUTUI.txt),方可通过所属权校验。
根据要求填写好下列选项

image.png

如:


image.png
  • 制作二维码
    使用二维码工具制作二维码:如 草料二维码
    将域名放入,可传参,小程序对应页面可接收参数,方法同路由跳转接收参数一样。生成二维码, 然后就可以使用微信扫描这个二维码进入小程序对应页面。

如:its.***.com/ft-xcx?a=1&b=2


image.png


4.4 地图

map组件提供了地图展示、交互、叠加点线面及文字等功能,同时支持个性化地图样式,可结合地图服务 API 实现更丰富功能,这里简单说一下, 不过多讲解,内容很多,详情去文档看既可。。 微信文档-map

个性化地图
个性化地图能力可在小程序后台“开发-开发者工具-腾讯位置服务”申请开通。 小程序内地图组件应使用同一 subkey,可通过 layer-style(地图官网设置的样式 style 编号)属性选择不同的底图风格。 组件属性的长度单位默认为px,2.4.0起支持传入单位(rpx/px)。。

image.png

示例

<!-- line-map -->
<view class='station_map'>
  <map 
    class='map' 
    subkey="3A4BZ-TMKEP-OPEDL-VCRQ7-HUJZ5-TJBYJ"
    id="station_map" 
    longitude="{{longitude}}" 
    latitude="{{latitude}}" 
    scale="14"  
    markers="{{markers}}"
    polyline="{{polyline}}"
    show-location
  ></map>
</view>
// pages/line/line.js
const Common = require("../../../utils/common.js");
//获取应用实例
const app = getApp();

Component({
  properties:{
    stations: {
      type: 'Object',
      value: {}
    },
    lineId: {
      type: 'String',
      value:''
    }
  },
  data: {
    // 图片链接
    img_server_url: app.globalData.img_server_url,
    latitude: 22.533773,
    longitude: 114.057678,
    markers: [],
    polyline: [],
    controls: []
  },
  ready(){
    var markers = [];
    for (var i = 0; i < this.data.stations.length; i++) {
      var station = this.data.stations[i];
      var poi = Common.wgs84togcj02(station.lng, station.lat);
      markers.push({
        id: i,
        iconPath:"./images/station_icon1.png",
        latitude: poi[1],
        longitude: poi[0],
        width: 20,
        height: 20,
        callout: {
          content: '站名:' + station.station_name,
          color: '#000',
          fontSize: '24rpx',
          padding: '10rpx',
          bgColor: '',
          borderRadius: '10rpx'
        }
      })
    }
    var poi = Common.wgs84togcj02(this.data.stations[0].lng, this.data.stations[0].lat);
    this.setData({
      markers: markers,
      latitude: poi[1],
      longitude: poi[0],
    });
    
    wx.showLoading({
      title: '加载中···',
      mask: true
    });
    var me = this;
    let param = {
      lineId: this.data.lineId
    };
    var url = app.globalData.request_server_url + "/wechat/getLineGeom";
    Common.fetchGet(url, param, function (records) {
      wx.hideLoading();
      let lineGeo = records.message.replace(/\w+/, '');
      lineGeo = lineGeo.replace(/\(|\)/g, '');
      lineGeo=lineGeo.split(',');
      var points = lineGeo.map( (item)=>{
        item = item.replace(/^\s+/,'');
        item=item.split(' ');
        var poi = Common.wgs84togcj02(item[0], item[1]);
        return {
          longitude: poi[0],
          latitude: poi[1]
        }
      });
      var polyline=[{
        points: points,
        color: '#09b1c7',
        borderColor:'#2f7f39',
        borderWidth:2,
        width: 5
      }];
      me.setData({
        polyline: polyline
      })
    });
  },
  method:{

  }
})


4.5 echarts使用

  • 下载echarts

下载echarts微信版 地址:https://github.com/ecomfe/echarts-for-weixin
下载后打开,如图所示:

wx-echarts.jpg

将下载好的文件中 ec-canvas目录 放在小程序项目目录中即可。如下图所示:


目录.jpg

然后在需要的地方引入即可。
效果


image.png
image.png
  • 示例

  • 在页面开启使用echarts
    如:在 page目录的ceshi页面中使用echarts的话,需要在ceshi.json中添加以下配置。

"usingComponents": {
    "ec-canvas": "../../ec-canvas/ec-canvas"
  }
  • 引入
    在 ceshi.js 中引入echarts.js
import * as echarts from '../../ec-canvas/echarts';
  • wxml元素
    在ceshi.wxml中建立一个元素,外层用view包一下是方便设置echarts元素的宽高。
  <view class="echart_panel">
    <ec-canvas></ec-canvas>
  </view>
  • 开始编写图表 折线图
    我是在ceshi.js中直接写了一个函数,传一些参数,返回一个option,至于echarts的option写法,可以参考echats官网api文档。
function getOption(xData, data_cur, data_his) {
  var option = {
    backgroundColor: "#f5f4f3",
    color: ["#37A2DA", "#f2960d", "#67E0E3", "#9FE6B8"],
    title: {
      text: '实时运行速度',
      textStyle: {
        fontWeight: '500',
        fontSize: 15,
        color: '#000'
      },
      x:'center',
      y:'0'
    },
    legend: {
      data: ['今日', '昨日'],
      right: 10
    },
    grid: {
      top: '15%',
      left: '1%',
      right: '3%',
      bottom: '60rpx',
      containLabel: true
    },
    tooltip: {
      show: true,
      trigger: 'axis'
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: xData||[],
      axisLabel: {
        interval: 11,
        formatter: function (value, index) {
          return value.substring(0, 2) * 1;
        },
        textStyle: {
          fontsize: '10px'
        }
      }
    },
    yAxis: {
      x: 'center',
      name: 'km/h',
      type: 'value',
      min: 0,
      max: 120
    },
    series: [{
      name: '今日',
      zIndex:2,
      type: 'line',
      smooth: true,
      symbolSize: 0,
      data: data_cur||[]
    },{
        name: '昨日',
        zIndex: 1,
        type: 'line',
        smooth: true,
        symbolSize: 0,
        data: data_his||[]
    }]
  };
  return option;
}

然后就可以在 页面page中的data中配置初始化,如何初始化?
首先 建立一个全局变量(注意,放在page外面,要全局变量,不然你在页面加载之后,在动态修改图表数据的话,没法修改,这样方便点),
然后在data中初始化echats对象 ecLine,名字随便起,按照官方写法即可,onInit函数中参数有三个,canvas, width, height,这些都不需要管,直接初始化echats元素。复制粘贴即可。

let chartLine;
Page({
    data: {
        ecLine: {
            onInit: function (canvas, width, height){
                //初始化echarts元素,绑定到全局变量,方便更改数据
                chartLine = echarts.init(canvas, null, {
                    width: width,
                    height: height
                });
                canvas.setChart(chartLine);

                //可以先不setOption,等数据加载好后赋值,
                //不过那样没setOption前,echats元素是一片空白,体验不好,所有我先set。
                var xData = [1,2,3,4,5......];  // x轴数据 自己写
                var option = getOption(xData);
                chartLine.setOption(option);
            }
        }
    }
})

然后将建立的echats对象绑定到echarts元素中,如下:

<view class="echart_panel">
    <ec-canvas ec="{{ ecLine }}"></ec-canvas>
  </view>
QQ截图20181220171735.jpg

然后就可以在数据加载后,给图表赋值option了,或者是重新setOption的数据。

//ajax请求好数据后,调用获取option函数,传一些数据,
//然后用全局变量echarts元素chartLine 来 setOption即可。
// 三个参数: x轴数据,第一条线数据,第二条数据。 随意,echarts就跟正常用随便写就行
// 随便写几个假数据
var xData=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23];
var data_cur=[55,67,66,78,55,67,66,78,55,67,66,78,55,67,66,78,55,67,66,78,65,66,65,54];
var data_his=[67,66,78,65,66,65,54,67,66,78,65,66,65,54,67,66,78,65,66,65,54,67,66,78];
// 方法一:
var option = getOption(xData, data_cur, data_his);
chartLine.setOption(option);
// 方法二:
//如果上面初始化时候,已经chartLine已经setOption了,
//那么建议不要重新setOption,官方推荐写法,重新赋数据即可。
chartLine.setOption({
    xAxis: {
        data: xData
    }, 
    series: [{
        data: data_cur
    }, {
        data: data_his
    }]
});

效果如下:

折线图.jpg

示例写的折线图,其他类型图表,可以参考echarts官网文档即可。

因为从github下载的echarts.js包含类型比较多,如果上传代码进行发布时,提示echarts文件过大,可以忽略。

或者是自己重新下载echarts定制需要的组件,如我就需要折线图,我就定制带折线图的即可。然后直接替换文件夹中的echarts.js即可。

下载定制echarts官网链接:http://echarts.baidu.com/builder.html



五、上传、发布

小程序打包发布等都很简单,流程:

  • 从微信开发工具上面上传代码到微信公众平台
  • 使用小程序账号登录,进入管理-版本管理,选择发布 正式版、体验版 既可。
  • 配置域名
    登录微信公众平台-点击开发管理-开发设置,往下拉进去配置合法域名

    image.png

  • 上传

image.png
image.png
  • 发布
    进入管理-版本管理,选择刚才提交的版本,点击提交审核发布既可,或者点击小三角,选择选为体验版。
image.png
image.png
image.png


六、小程序开发技术选型(不限于微信小程序)

  • 原生开发
    使用小程序原生开发,很方便,官方提供了非常详细的组件、API等,文档也很丰富,开发者社区等。

优点

  • 官方文档清晰明了,更接近手机服务的底层逻辑,开发者可以更有针对性的对小程序进行深度开发
  • 小程序原生平台社区更加活跃
  • 使用原生开发可以紧随官方的版本,更新响应速度快,让项目达到最优状态
  • 完美适配,不会出现适配问题
  • 原生开发的功能更加完善,可以优秀的调用小程序API使用手机各种功能

缺点

  • 仅适用于单个平台的小程序
  • 开发成本高,开发不同平台下的小程序,需要不同的开发工具及语法
  • 维护成本高,同样的项目需要写多套代码,后期维护起来工作量大成本高,
  • 原生组件样式不太美观,需要专门写css美化
  • uni-app
    uniapp是跨端的快速开发工具,当前支持微信小程序、百度小程序、头条小程序、qq小程序等14个平台,一套代码适应多个平台。 支持原生代码混写和原生sdk集成,通过条件编译+平台特有API调用,可以优雅的为某平台写个性化代码,调用专有能力而不影响其他平台。

优点

  • 多端开发,一套代码可打包超多个不同平台,生成各种小程序H5及APP应用,不需来回切换各种开发工具
  • 学习成本低,uni-app基于通用的前端技术栈,采用vue语法+微信小程序api,无额外学习成本
  • 插件市场, uni-app拥有上千款的插件,支持NPM、支持平台小程序组件和SDK
  • 组件丰富,样式漂亮
  • 微信小程序依赖于微信的一键登录非常方便,uniapp不但能使用微信登录,而且还有一套自己的用户管理系统

缺点

  • 完善性差,uni-app问世的时间还比较短,坑多,不过官方版本更新活跃,相信这些问题逐渐都会得到解决
  • 兼容问题,uni-app打包出来的小程序可能会存在平台兼容问题,同样的代码会在不同平台下存在差异,如微信小程序、支付宝小程序。
  • 如更新不及时,就不能紧随平台小程序,使用不了小程序平台发布的新功能
  • 文档比较松散,社区质量不如小程序平台
  • 其他类似uni-app的框架
    taro、yonbuilder

  • 总结
    项目只做单平台的小程序,原生是最优的选择
    项目同时开发多平台小程序,使用uni-app最优选择

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容