微信小程序笔记

部分内容来自微信小程序官方文档,主要是对微信小程序一个系统的认识和总结

2) 介绍小程序代码构成 app.jsonapp.jsapp.wxss2-1) 介绍小程序页面构成 page.js 、 page.wxmlpage.json 、 page.wxss 、page.wxs,3)project.config.json 项目配置信息,4)sitemap.json 小程序索引配置

1).小程序与普通网页开发的区别

​小程序的主要开发语言是 JavaScript。

网页开发渲染线程和脚本线程是互斥的,长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。

网页开发者可以使用到各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作。而如上文所述,小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。这一区别导致了前端开发非常熟悉的一些库,例如 jQuery、 Zepto 等,在小程序中是无法运行的。同时 JSCore 的环境同 NodeJS 环境也是不尽相同,所以一些 NPM 的包在小程序中也是无法运行的。

​网页开发者需要面对的环境是各式各样的浏览器,PC 端需要面对 IE、Chrome、QQ浏览器等,在移动端需要面对Safari、Chrome以及 iOS、Android 系统中的各式 WebView 。而小程序开发过程中需要面对的是两大操作系统 iOS 和 Android 的微信客户端,以及用于辅助开发的小程序开发者工具,小程序中三大运行环境也是有所区别的

运行环境

逻辑层

渲染层

iOS

JavaScriptCore

WKWebView

安卓

V8

chromium定制内核

小程序开发者工具

NWJS

Chrome WebView

小程序代码构成

小程序包含一个描述整体程序的app和多个描述各自页面的page。

一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:

文件必需作用
app.js小程序逻辑
app.json小程序公共配置
app.wxss小程序公共样式表(注1)

  注1:

    作用于全局的样式表,同CSS用法一样,若在任意Page页写了同名Class则覆盖此处的样式。

    行内样式 > Page.css > app.css

  小程序全局配置 app.json

  app.json是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等

// 小程序配置app.json
// JSON 配置 // JSON 是一种数据格式,并不是编程语言,在小程序中,JSON扮演的静态配置的角色 /* JSON 语法 注意事项: JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据。JSON的Key必须包裹在一个双引号中,在实践中,编写 JSON 的时候,忘了给 Key 值加双引号或者是把双引号写成单引号是常见错误。 JSON的值只能是以下几种数据格式,其他任何格式都会触发报错,例如 JavaScript 中的 undefined。 数字,包含浮点数和整数 字符串,需要包裹在双引号中 Bool值,true 或者 false 数组,需要包裹在方括号中 [] 对象,需要包裹在大括号中 {} Null 还需要注意的是 JSON 文件中无法使用注释,试图添加注释将会引发报错。 */ { //pages用于指定小程序由哪些页面组成,每一项都对应一个页面路径(文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对于位置的 .json, .js, .wxml, .wxss 四个文件进行处理。数组的第一项代表小程序的初始页面(首页)。小程序中新增/减少页面,都需要对 pages 数组进行修改。 "pages": [ "pages/index/index", "pages/logs/logs" ], //window对象。设置小程序全局的状态栏、导航条、标题、窗口背景色。 "window": { //导航栏背景颜色,十六进制颜色 "navigationBarBackgroundColor": "#ffffff", //导航栏标题颜色 仅包含black (黑色)/ white(白色) "navigationBarTextStyle": "black", //导航栏标题文字内容 "navigationBarTitleText": "听风吟", //导航栏样式 仅包含default(默认)/custom(清空之前的所有样式设置) "navigationStyle": "default", //窗口的背景色 (未发现明显改变) "backgroundColor": "#eeeeee", //下拉 loading 的样式 仅支持 dark(刷新时改为三个 ·) / light(无特殊属性)需开启enablePullDownRefresh下拉刷新 "backgroundTextStyle": "light", //开启/关闭全局下拉刷新 仅true/false "enablePullDownRefresh": true, //页面上拉触底事件触发时距页面底部距离,单位为 px。 "onReachBottomDistance": 30, // 响应显示区域变化 //屏幕旋转设置,支持 auto (自动)/ portrait(竖屏) / landscape (2.5.0支持固定横屏显示) "pageOrientation": "portrait", // iPad 上启用屏幕旋转支持 "resizable": true }, //tabBar如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面(指定页面栏目最少2个最多5个并配置样式) "tabBar": { //tab 上的文字默认颜色,仅支持十六进制颜色 "color": "#ffffff", //tab 上的文字选中时的颜色,仅支持十六进制颜色 "selectedColor": "#00ffff", //tab 的背景色,仅支持十六进制颜色 "backgroundColor": "#000000", //tabbar 上边框的颜色, 仅支持 black / white "borderStyle": "black", //tab的列表项接受一个数组,配置最少 2 个、最多 5 个 tab "list": [ { //页面路径,必须在 pages 中先定义 "pagePath": "pages/index/index", //tab 上按钮文字 "text": "首页", //图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon。 "iconPath": "../images/xxx.ico", //选中时的图片路径,限制同上 "selectedIconPath": "../images/xxx2.ico" }, { "pagePath": "pages/logs/logs", "text": "日志", "iconPath": "../images/xxx.ico", "selectedIconPath": "../images/xxx2.ico" } ], // tabBar 的位置,仅支持 bottom / top "position":"bottom", //自定义 tabBar 用自定义组件的方式编写即可,该自定义组件完全接管 tabBar 的渲染。另外,自定义组件新增 getTabBar 接口,可获取当前页面下的自定义 tabBar 组件实例 //添加自定义目录custom-tab-bar "custom":true }, //networkTimeout各类网络请求的超时时间,单位均为毫秒。 //默认均为60s "networkTimeout": { //wx.request 的超时时间,单位:毫秒。 "request": 10000, //wx.downloadFile 的超时时间,单位:毫秒。 "downloadFile": 10000, //wx.connectSocket 的超时时间,单位:毫秒。 "connectSocket": 10000, //wx.uploadFile 的超时时间,单位:毫秒。 "uploadFile": 10000 }, //debug在开发者工具中开启 debug 模式,在开发者工具的控制台面板,调试信息以 info 的形式给出,其信息有 Page 的注册,页面路由,数据更新,事件触发等。 "debug": false, //要在插件中调用插件功能页,需要先激活插件所有者小程序的功能页 "functionalPages": { "independent": true }, //subpackages申明项目分包结构 /**某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。 在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。 在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。 目前小程序分包大小有以下限制: 整个小程序所有分包大小不超过 8M 单个分包/主包大小不能超过 2M 对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。*/ /** 打包原则 声明 subpackages 后,将按 subpackages 配置路径进行打包,subpackages 配置路径外的目录将被打包到 app(主包) 中 app(主包)也可以有自己的 pages(即最外层的 pages 字段) subpackage 的根目录不能是另外一个 subpackage 内的子目录 tabBar 页面必须在 app(主包)内 */ /* 引用原则 packageA 无法 require packageB JS 文件,但可以 require app、自己 package 内的 JS 文件 packageA 无法 import packageB 的 template,但可以 require app、自己 package 内的 template packageA 无法使用 packageB 的资源,但可以使用 app、自己 package 内的资源*/ /* 低版本兼容 由微信后台编译来处理旧版本客户端的兼容,后台会编译两份代码包,一份是分包后代码,另外一份是整包的兼容代码。 新客户端用分包,老客户端还是用的整包,完整包会把各个 subpackage 里面的路径放到 pages 中。 */ "subpackages": [ { //分包跟目录 "root": "packageA", //分包别名,分包预加载时可用 "name": "pack1", //分包页面路径,相对于分包跟目录,使用同pages一样 "pages": [ "pages/test/test" ], //是否为独立分包 /* 独立分包 微信客户端 6.7.2,基础库 2.3.0 及以上版本开始支持。开发者工具请使用 1.02.1808300 及以上版本,可点此下载。 独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。 开发者可以按需将某些具有一定功能独立性的页面配置到独立分包中。当小程序从普通的分包页面启动时,需要首先下载主包;而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度。 一个小程序中可以有多个独立分包 */ /* 限制 独立分包属于分包的一种。普通分包的所有限制都对独立分包有效。独立分包中插件、自定义组件的处理方式同普通分包。 此外,使用独立分包时要注意: 1、独立分包中不能依赖主包和其他分包中的内容,包括js文件、template、wxss、自定义组件、插件等。主包中的app.wxss对独立分包无效,应避免在独立分包页面中使用 app.wxss 中的样式; 2、App 只能在主包内定义,独立分包中不能定义 App,会造成无法预期的行为; 3、独立分包中暂时不支持使用插件 */ /* 关于 getApp() 与普通分包不同,独立分包运行时,App 并不一定被注册,因此 getApp() 也不一定可以获得 App 对象: 当用户从独立分包页面启动小程序时,主包不存在,App也不存在,此时调用 getApp() 获取到的是 undefined。 当用户进入普通分包或主包内页面时,主包才会被下载,App 才会被注册。 当用户是从普通分包或主包内页面跳转到独立分包页面时,主包已经存在,此时调用 getApp() 可以获取到真正的 App。 由于这一限制,开发者无法通过 App 对象实现独立分包和小程序其他部分的全局变量共享。 为了在独立分包中满足这一需求,基础库 2.2.4 版本开始 getApp支持 [allowDefault ]参数,在 App 未定义时返回一个默认实现。当主包加载,App 被注册时,默认实现中定义的属性会被覆盖合并到真正的 App 中 定义方法: const app = getApp({allowDefault: true}) */ /* 关于 App 生命周期 当从独立分包启动小程序时,主包中 App 的 onLaunch 和首次 onShow 会在从独立分包页面首次进入主包或其他普通分包页面时调用。 由于独立分包中无法定义 App,小程序生命周期的监听可以使用 wx.onAppShow,wx.onAppHide 完成。App 上的其他事件可以使用 wx.onError,wx.onPageNotFound 监听 */ "independent":false }, { "root": "packageB", "name": "pack2", "pages": [ "pages/demo/demo" ], "independent": false } ], //preloadRule分包预下载 /* 进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包 预下载分包行为在进入某个页面时触发,通过在 app.json 增加 preloadRule 配置来控制。 */ "preloadRule": { //页面路径 "pages/index/index": { //预下载配置 //在指定网络下预下载,可选值为:all: 不限网络 wifi: 仅wifi下预下载 "network": "all", //进入页面后预下载分包的 root 或 name。__APP__ 表示主包 "packages": [ "packageA" ] }, "pages/logs/logs": { "network": "wifi", "packages": [ "__APP__", "packageA", "packageB" ] } }, //多线程workers /* 一些异步处理的任务,可以放置于 Worker 中运行,待运行结束后,再把结果返回到小程序主线程。Worker 运行于一个单独的全局上下文与线程中,不能直接调用主线程的方法。 Worker 与主线程之间的数据传输,双方使用 Worker.postMessage() 来发送数据,Worker.onMessage() 来接收数据,传输的数据并不是直接共享,而是被复制的 */ "workers": "workers", /*在app.js中创建worker实例,只能创建一个 Worker wx.createWorker(string scriptPath) 监听主线程/Worker 线程向当前线程发送的消息的事件 worker.onMessage(function (res) {console.log(res)}) 向主线程/Worker 线程发送的消息 worker.postMessage({msg: 'hello worker'}) 需要发送的消息,必须是一个可序列化的 JavaScript key-value 形式的对象(JSON格式) Worker.terminate() 结束当前 Worker 线程。仅限在主线程 worker 对象上调用 */ //requiredBackgroundModes申明需要后台运行的能力,类型为数组。目前支持以下项目:audio: 后台音乐播放 location: 后台定位 //在此处申明了后台运行的接口,开发版和体验版上可以直接生效,正式版还需通过审核。 "requiredBackgroundModes": [ "audio", "location" ], // 使用插件 /* plugins 定义段中可以包含多个插件声明,每个插件声明以一个使用者自定义的插件引用名作为标识,并指明插件的 appid 和需要使用的版本号。其中,引用名(如上例中的 myPlugin)由使用者自定义,无需和插件开发者保持一致或与开发者协调。在后续的插件使用中,该引用名将被用于表示该插件 */ "plugins": { "myPlugin": { "version": "1.0.0", "provider": "wxidxxxxxxxxxxxxxxxx" } }, // 当小程序需要使用 wx.navigateToMiniProgram 接口跳转到其他小程序时,需要先在配置文件中声明需要跳转的小程序 appId 列表,最多允许填写 10 个。 "navigateToMiniProgramAppIdList":[ "wxcbe110fu2xaxedfu", "wxfb1ff0f3u0abe913", "wxc1b5d81exdad1efe", "wxu8caa30cd32c1fb9", "wx52axxb89fx3xe23c" ], // usingComponents // 在此处声明的自定义组件视为全局自定义组件,在小程序内的页面或自定义组件中可以直接使用而无需再声明 // 授权permission // 部分接口需要经过用户授权同意才能调用。我们把这些接口按使用范围分成多个 scope ,用户选择对 scope 来进行授权,当授权给一个 scope 之后,其对应的所有接口都可以直接使用。 // 获取用户授权设置 // wx.getSetting // 打开设置界面 // wx.openSetting // 提前发起授权请求 // wx.authorize /* scope 列表 scope.userInfo wx.getUserInfo 用户信息 scope.userLocation wx.getLocation, wx.chooseLocation 地理位置 scope.userLocationBackground wx.userLocationBackground 后台定位 scope.address wx.chooseAddress 通讯地址 scope.invoiceTitle wx.chooseInvoiceTitle 发票抬头 scope.invoice wx.chooseInvoice 获取发票 scope.werun wx.getWeRunData 微信运动步数 scope.record wx.startRecord 录音功能 scope.writePhotosAlbum wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum 保存到相册 scope.camera camera 组件 摄像头 */ "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" // 高速公路行驶持续后台定位 } }, // 配置微信小程序内索引 /* sitemap.json 用于配置小程序及其页面是否允许被微信索引,文件内容为一个 JSON 对象,如果没有 sitemap.json ,则默认为所有页面都允许被索引; */ "sitemapLocation": "sitemap.json", // 微信客户端 7.0 开始,UI 界面进行了大改版。小程序也进行了基础组件的样式升级。app.json 中配置 "style": "v2"可表明启用新版的组件样式。本次改动涉及的组件有 button icon radio checkbox switch slider。 "style": "v2" }

  

    小程序app.js

    每个小程序都需要在app.js中调用 App方法注册小程序示例,绑定生命周期回调函数、错误监听和页面不存在监听函数等

//注册小程序app.js

/**
 * 
 * App() 必须在 app.js 中调用,必须调用且只能调用一次
 * 
 * 整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 示例,获取App上的数据或调用开发者注册在 App 上的函数。
 */
App({
  // 生命周期回调——监听小程序初始化。
  /**
   * 小程序初始化完成时触发,全局只触发一次。回调参数也可以使用 wx.getLaunchOptionsSync 获取
   * 返回参数
   * Object
属性                         类型               说明
path                        string            启动小程序的路径
scene                        number            启动小程序的场景值(具体场景值参考:场景值列表)
query                        Object            启动小程序的 query 参数
shareTicket                  string            shareTicket,获取转发信息(详见:注1)
referrerInfo                Object            来源信息。从另一个小程序、公众号或 App 进入小程序时返回。否则返回 {}。(详见:注2)
   */
  /**
   * 注1
   * 获取更多转发信息
   * 通常开发者希望转发出去的小程序被二次打开的时候能够获取到一些信息,例如群的标识。现在通过调用 wx.showShareMenu 并且设置 withShareTicket 为 true ,当用户将小程序转发到任一群聊之后,此转发卡片在群聊中被其他用户打开时,可以在 App.onLaunch 或 App.onShow 获取到一个 shareTicket。通过调用 wx.getShareInfo 接口传入此 shareTicket 可以获取到转发信息
   * 
   * 说人话系列:
   * 即可以通过设置转发withShareTicket为true在另一个页面中通过shareTicket获取wx.getShareInfo 接口回调以取得更多转发信息
   * 如:A用户在将Test小程序转发至C微信群,此时B用户通过点击C微信群中的小程序卡片进入小程序,此时开发者可通过App.onLaunch或wx.getLaunchOptionsSync获取shareTicket,
   * 然后将shareTicket传入wx.getShareInfo获取回调,回调中的敏感数据为加密的需后台校验解密开放数据(解密详见:服务端获取开放数据)
   */
  /**
   * 注2
   * referrerInfo 结构
属性            类型         说明
appId          string      来源小程序、公众号或 App 的 appId
extraData      Object      来源小程序传过来的数据,scene=1037或1038时支持

注意:
部分版本在无referrerInfo的时候会返回 undefined,建议使用 options.referrerInfo && options.referrerInfo.appId 进行判断
   */
  onLaunch: function(options) {
    //小程序初始化完后,打印回调参数,同wx.getLaunchOptionsSync函数一样
    console.log(options)

    // 展示本地存储能力
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)

    // 登录
    wx.login({
      success: res => {
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
      }
    })
    // 获取用户信息
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          wx.getUserInfo({
            success: res => {
              // 可以将 res 发送给后台解码出 unionId
              this.globalData.userInfo = res.userInfo

              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
              // 所以此处加入 callback 以防止这种情况
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }
            }
          })
        }
      }
    })

  },
  // 生命周期回调——监听小程序启动或切前台。
  /**
   * 小程序启动,或从后台进入前台显示时触发。也可以使用 wx.onAppShow 绑定监听
   * 回调参数同onLaunch或wx.getLaunchOptionsSync一样,区别在于 onLaunch 全局只生效一次,而onShow每次进入小程序前台或启动都会触发
   */
  onShow: function(options) {
    console.log("Look Me")
  },

  // 生命周期回调——监听小程序切后台
  /**
   * 小程序从前台进入后台时触发。也可以使用 wx.onAppHide 绑定监听
   */
  onHide: function() {
    console.log("awsl")
  },

  // 错误监听函数。
  /**
   * 小程序发生脚本错误或 API 调用报错时触发。也可以使用 wx.onError 绑定监听
   */
  onError(msg) {
    console.log(msg)
  },
  // 页面不存在监听函数
  /**
   * 小程序要打开的页面不存在时触发。也可以使用 wx.onPageNotFound 绑定监听
   * 返回参数
   * 
属性              类型            说明
path            string          不存在页面的路径
query            Object          打开不存在页面的 query 参数
isEntryPage      boolean          是否本次启动的首个页面(例如从分享等入口进来,首个页面是开发者配置的分享页面)
注意:
开发者可以在回调中进行页面重定向,但必须在回调中同步处理,异步处理(例如 setTimeout 异步执行)无效。
若开发者没有调用 wx.onPageNotFound 绑定监听,也没有声明 App.onPageNotFound,当跳转页面不存在时,将推入微信客户端原生的页面不存在提示页面。
如果回调中又重定向到另一个不存在的页面,将推入微信客户端原生的页面不存在提示页面,并且不再第二次回调

(通常可以在此处配置自己的不存在页面)
   */
  onPageNotFound(res) {
    wx.redirectTo({
      url: 'pages/...'
    }) // 如果是 tabbar 页面,请使用 wx.switchTab
  },


  // 其他    类型:any  非必填     可以添加任意的函数或数据变量到 Object 参数中,用 this(即app实例) 可以访问
  /**
   * 可添加全局函数,获取app应用实例后即可使用
   * 
   * 如下:
   * const app = getApp();
   * 
   * app.test(23333)
   * 
   * 控制台将打印"23333"
   */
  test: function(e) {
    console.log(e)
  },
  //全局变量,全局可用,一般用于保存用户信息
  globalData: {
    userInfo: null
  }


})

  

  小程序全局样式app.wxss

  WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。

/* app.wxss */

/* 
WXSS 用来决定 WXML 的组件应该怎么显示。WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。

与 CSS 相比,WXSS 扩展的特性有:

尺寸单位
样式导入

尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

设备               rpx换算px (屏幕宽度/750)            px换算rpx (750/屏幕宽度)
iPhone5            1rpx = 0.42px                       1px = 2.34rpx
iPhone6            1rpx = 0.5px                       1px = 2rpx
iPhone6 Plus      1rpx = 0.552px                     1px = 1.81rpx

样式导入
使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。
 */
/* 建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。 */

/* 
内联样式
框架组件上支持使用 style、class 属性来控制组件的样式。

style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
<view  />
class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。
<view class="normal_view" />
 */

/* 
选择器
目前支持的选择器有:

选择器                样例                        样例描述
.class               .intro                       选择所有拥有 class="intro" 的组件
#id                   #firstname                   选择拥有  的组件
element               view                         选择所有 view 组件
element, element     view, checkbox               选择所有文档的 view 组件和所有的 checkbox 组件
::after               view::after                 在 view 组件后边插入内容
::before             view::before                 在 view 组件前边插入内容
 */

/* 
全局样式与局部样式
定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
 */
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 200rpx 0;
  box-sizing: border-box;
} 

2-1).小程序页面构成

文件类型必需作用
js页面逻辑
wxml页面结构
json页面配置
wxss页面样式表

  Page.wxml

  WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构

<!--index.wxml-->
<view class='page'>
  <view class="container">
    <view class="userinfo">
      <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
      <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>
</view>
<!-- WXML -->
<!-- WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。 -->
<!-- 仅介绍基础语法及事件系统,WXML基础组件及JS API使用 将由另外的篇幅来写,内容太多._ ._ ._ ._ ._ ._-->
<!-- 以下将查看数据绑定、列表渲染、条件渲染、模板、引用等页面能力 
     所有功能测试数据可直接复制至js中使用,对应组件复制到wxml中,终值为最终显示的值(或最终运行的结果)
-->

<!-- 数据绑定 -->
<!-- WXML 中的动态数据均来自对应 Page 的 data -->
<!-- 
简单绑定
数据绑定使用 Mustache 语法(双大括号)将变量包起来,可以作用于:
测试数据:
Page({
  data: {
    message: 'Hello WeChat!',
    id: 0,
    condition: true,
    flag: false,
    a:1,
    b:2,
    c:3,
    length:7,
    name:"World",
    object: {
      key: 'Hello '
    },
    array: ['MINA'],
    zero: 0,
    testa: 1,
    testb: 2,
    obj1: {
      a: 1,
      b: 2
    },
    obj2: {
      c: 3,
      d: 4
    },
    foo: 'my-foo',
    bar: 'my-bar',
    obj3: {
      a: 1,
      b: 2
    },
    obj4: {
      b: 3,
      c: 4
    },
    o: 5
    }
  })
可将内容复制到index.js的data中以下内容复制到wxml中即可查看效果
注:template组件因未存在相应模板将不会显示,自行调整代码以展示效果(添加对应模板文件,在模板文件中渲染数据即可)


-内容
  <view> {{ message }} </view>
  -终值:Hello WeChat!

-组件属性
  <view > </view>
  -终值:<view > </view>

-控制属性
  <view wx:if="{{condition}}">此组件将会显示</view>
  -终值:此组件将会显示

-关键字
  <checkbox checked="{{false}}"> </checkbox>
  //true:boolean 类型的 true,代表真值。
  //false: boolean 类型的 false,代表假值。
  //特别注意:不要直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值
  -终值:组件未选中
  

-运算(支持简单运算)
  -三元运算
  <view hidden="{{flag ? true : false}}"> Hidden </view>
  -终值:Hidden(组件显示)

  -算数运算
  <view> {{a + b}} + {{c}} + d </view>
  -终值:3 + 3 + d

  -逻辑判断
  <view wx:if="{{length > 5}}">大于5</view>
  -终值:大于5

  -字符串运算
  <view>{{"hello" + name}}</view>
  -终值:hello World

  -数据路径
  <view>{{object.key}} {{array[0]}}</view>
  -终值:Hello MINA

  -组合
  //可以在 Mustache 内直接进行组合,构成新的对象或者数组
  <view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
  -终值:(依次打印数组内容"0"、"1"、"2"、"3"、"4")

  -对象
  <template is="objectCombine" data="{{for: testa, bar: testb}}"></template>
  -终值:(向模板'objectCombine'传递对象{for: 1, bar: 2})
  
  -扩展运算符 ...
  //将当前对象展开
  <template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
  -终值:(向模版'objectCombine'传递对象{a: 1, b: 2, c: 3, d: 4, e: 5})

  <template is="objectCombine" data="{{foo, bar}}"></template>
  -终值:(向模版'objectCombine'传递对象{foo: 'my-foo', bar:'my-bar'})
  
  //注意: 
  上述方式扩展运算符可以随意组合,但是如有存在变量名相同的情况,后边的数据会覆盖前面的数据
  <template is="objectCombine" data="{{...obj3, ...obj4, o, c: 6}}"></template>
  -终值:(向模版'objectCombine'传递对象{a: 5, b: 3, c: 6})

  花括号和引号之间如果有空格,将最终被解析成为字符串
  <view wx:for="{{[1,2,3]}} ">
  {{item}}
  </view>
  -终值:(页面依次循环输出for中的数据"1"、","、"2"、","、"3"、" "最后将输出6个view)

 -->


<!-- 
 列表渲染
  测试数据
  Page({
  data: {
    array: [{
      message: 'foo',
    }, {
      message: 'bar'
    }],
    condition2:true,
    length:4,
    objectArray: [
      {id: 5, unique: 'unique_5'},
      {id: 4, unique: 'unique_4'},
      {id: 3, unique: 'unique_3'},
      {id: 2, unique: 'unique_2'},
      {id: 1, unique: 'unique_1'},
      {id: 0, unique: 'unique_0'},
    ],
  },
  switch: function(e) {
    const length = this.data.objectArray.length
    for (let i = 0; i < length; ++i) {
      const x = Math.floor(Math.random() * length)
      const y = Math.floor(Math.random() * length)
      const temp = this.data.objectArray[x]
      this.data.objectArray[x] = this.data.objectArray[y]
      this.data.objectArray[y] = temp
    }
    this.setData({
      objectArray: this.data.objectArray
    })
  },
})

-wx:for
  在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
  默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
  <view wx:for="{{array}}">
  {{index}}: {{item.message}}
  </view>
  -终值:0:foo 1:bar
  //可使用 wx:for-item 指定数组当前元素的变量名
  //可使用 wx:for-index 指定数组当前下标的变量名
  //如<view wx:for="{{array}}" wx:for-item="inde" wx:for-index="indexx">
  //{{indexx}}: {{inde.message}}
  //</view>
  //最终结果是一样的
  //注:当 wx:for 的值为字符串时,会将字符串解析成字符串数组(将整个字符串,逐行打印)
  //注:花括号和引号之间如果有空格,将最终被解析成为字符串

-wx:for 嵌套,下边是一个九九乘法表
  <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
  <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
    <view wx:if="{{i <= j}}">
      {{i}} * {{j}} = {{i * j}}
    </view>
  </view>
  </view>

-wx:key
  如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指   定列表中项目的唯一的标识符。

  wx:key 的值以两种形式提供
  字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
  保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
  当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

  如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略.
  <switch wx:for="{{objectArray}}" wx:key="unique" > {{item.id}} </switch>
  <button bindtap="switch"> Switch </button>
  <switch wx:for="{{objectArray}}" > {{item.id}} </switch>
  //以上代码来自官方,自己做了些调整,更加直观,也可直接去官方查看:https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/list.html
  //说人话系列:简单来说,当你的数据源发生改变时,添加了wx:key的循环体会被重新排序(已添加的数据不会被改变),而不是重新创建(初始化所有数据)
  -->


<!-- 
条件渲染
-wx:if
  在框架中,使用 wx:if="" 来判断是否需要渲染该代码块:
  <view wx:if="{{condition2}}"> True </view>
  -终值:(此组件将显示)
  也可以用 wx:elif 和 wx:else 来添加一个 else 块:
  <view wx:if="{{length > 5}}"> 1 </view>
  <view wx:elif="{{length > 2}}"> 2 </view>
  <view wx:else> 3 </view>
  -终值:(只显示2)
  //与js中的if、else if、else相同,只判断一次,若前者通过,则后者不运行
-block wx:if
  如果要一次性判断多个组件标签,可以使用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
  //注: <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
-wx:if vs hidden
  因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
  同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
  相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
  一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。
 -->


<!-- 
模板
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。
测试数据:
  Page({
  data: {
    item: {
      index: 0,
      msg: 'this is a template',
      time: '2016-09-15'
    }
  },
  showmodal: function () {
    wx.showModal({
      title: '提示',
      content: '触发JS',
    })
  }
  })
-定义模板
  使用 name 属性,作为模板的名字。然后在<template/>内定义代码片段,如:
  <template name="msgItem">
  <view bindtap="showmodal">
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
  </template>
-使用模板
  使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:
  <template is="msgItem" data="{{...item}}"/>

  //使用不同页面的模板时
  //引入模板文件
  <import src="../template/template.wxml" />
  //相应模板可以拥有独立的css
  @import "../template/template.wxss";
  //模板不能独立创建JS文件,但相应事件可以在当前页面中被触发

-动态渲染
  is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:
  <template name="odd">
    <view> odd </view>
  </template>
  <template name="even">
    <view> even </view>
  </template>

  <block wx:for="{{[1, 2, 3, 4, 5]}}">
    <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
  </block>
 -->


<!-- 
引用
-import
  import可以在该文件中使用目标文件定义的template
  //仅引入文件而没使用,需调用对应组件才能生效
  <import src="../template/template.wxml" />
  作用域:
  import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。

-include
  include 可以将目标文件除了 <template/> <wxs/> 外的整个代码引入,相当于是拷贝到 include 位置
  <include src="header.wxml"/>
    <view> body </view>
  <include src="footer.wxml"/>

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

<!-- 基础语法 End -->



<!-- 事件系统 -->
<!-- 
-事件
  //事件系统微信官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html
  事件是视图层到逻辑层的通讯方式。
  事件可以将用户的行为反馈到逻辑层进行处理。
  事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
  事件对象可以携带额外信息,如 id, dataset, touches
  //说人话:事件是一种用户与程序的互动行为,当用户点击某一个按钮、图片等,如果按钮、图片绑定了相应事件,用户的行为就会触发事件如:
  测试数据:
  Page({
    tapName: function(e) {
      console.log(e.currentTarget.dataset.hi)
    }
  })

  <view > Click me! </view>
  -终值:(控制台打印)Hi WeChat

-事件分类
  事件分为冒泡事件和非冒泡事件:
    冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
    非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
    如:
    //index.wxml
    <view >
      <view >
        <view >
          <view >
            <view >
            </view>
          </view>
        </view>
      </view>
    </view>
  //index.wxss
  .view1 {
  height: 200rpx;
  width: 700rpx;
  background-color: #13c106;
  }
  .view2 {
  height: 200rpx;
  width: 550rpx;
  background-color: #1495e7;
  }
  .view3 {
  height: 200rpx;
  width: 400rpx;
  background-color: #f00;
  }
  .view4 {
  height: 200rpx;
  width: 250rpx;
  background-color: #fff;
  }
  .view5 {
  height: 200rpx;
  width: 100rpx;
  background-color: #ffce44;
  }
  //以上数据展示冒泡事件及非冒泡事件的区别,JS可写可不写,开发者工具会发出相应警告,观察警告条数即可
  //注意tap4事件绑定方式为catch

  //微信冒泡事件列表:
  类型                      触发条件                                                                              最低版本
  touchstart                手指触摸动作开始    
  touchmove                  手指触摸后移动    
  touchcancel                手指触摸动作被打断,如来电提醒,弹窗    
  touchend                  手指触摸动作结束    
  tap                        手指触摸后马上离开    
  longpress                  手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发      1.5.0
  longtap                    手指触摸后,超过350ms再离开(推荐使用longpress事件代替)    
  transitionend              会在 WXSS transition 或 wx.createAnimation 动画结束后触发    
  animationstart            会在一个 WXSS animation 动画开始时触发    
  animationiteration        会在一个 WXSS animation 一次迭代结束时触发    
  animationend              会在一个 WXSS animation 动画完成时触发    
  touchforcechange          在支持 3D Touch 的 iPhone 设备,重按时会触发                                           1.9.90
  //注:除上述之外的其他组件自定义事件如无特殊声明都是非冒泡事件,如 form 的submit事件,input 的input事件,scroll-view 的scroll事件

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

  key 以bind或catch开头,然后跟上事件的类型,如bindtap、catchtouchstart。自基础库版本 1.5.0 起,在非原生组件中,bind和catch后可以紧跟一个冒号,其含义不变,如         bind:tap、catch:touchstart。
  value 是一个字符串,需要在对应的 Page 中定义同名的函数。不然当触发事件的时候会报错。基础库版本 2.8.1 起,原生组件也支持bind后紧跟冒号的写法。

  //bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。
  //具体例子见事件分类

-事件捕获
  事件的捕获阶段
  自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用       capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。

  在下面的代码中,点击 inner view 会先后调用handleTap2、handleTap4、handleTap3、handleTap1。

  <view >
    outer view
    <view >
      inner view
    </view>
  </view>
  如果将上面代码中的第一个capture-bind改为capture-catch,将只触发handleTap2。

  <view >
    outer view
    <view >
      inner view
    </view>
  </view>

  //说人话:触摸类的事件在触发之前会有一个捕获阶段,捕获阶段执行完成后才会触发事件,事件触发顺序如下:
  //用户点击-捕获阶段(冒泡/非冒泡)-触发事件(冒泡/非冒泡)
  //注:捕获阶段触发非冒泡事件,则不会触发之后的任何事件,且捕获阶段执行节点与冒泡顺序相反

-事件对象
  如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象。
  BaseEvent 基础事件对象属性列表:
  属性              类型        说明                                基础库版本
  type              String      事件类型    
  timeStamp          Integer      事件生成时的时间戳    
  target            Object      触发事件的组件的一些属性值集合    
  currentTarget      Object      当前组件的一些属性值集合    
  mark              Object      事件标记数据                        2.7.1

  CustomEvent 自定义事件对象属性列表(继承 BaseEvent):
  属性              类型        说明
  detail            Object      额外的信息

  TouchEvent 触摸事件对象属性列表(继承 BaseEvent):
  属性              类型        说明
  touches            Array        触摸事件,当前停留在屏幕中的触摸点信息的数组
  changedTouches    Array        触摸事件,当前变化的触摸点信息的数组

  //特殊事件: canvas 中的触摸事件不可冒泡,所以没有 currentTarget

  -对象模型
  {
  //触发的事件类型
  type:"tap"

  //在基础库版本 2.7.1 以上,可以使用 mark 来识别具体触发事件的 target 节点。此外, mark 还可以用于承载一些自定义数据(类似于 dataset )。
    当事件触发时,事件冒泡路径上所有的 mark 会被合并,并返回给事件回调函数。(即使事件不是冒泡事件,也会 mark 。)
    /*
    //index.wxml
    <view mark:myMark="last" bindtap="bindViewTap">
      <button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮</button>
    </view>

    //index.js
    Page({
    bindViewTap: function(e) {
      console.log(e)
      console.log(e.mark.myMark === "last") // true
      console.log(e.mark.anotherMark === "leaf") // true
    }
    })
    在上述 WXML 中,如果按钮被点击,将触发 bindViewTap 和 bindButtonTap 两个事件,事件携带的 event.mark 将包含 myMark 和 anotherMark 两项

    mark 和 dataset 很相似,主要区别在于: mark 会包含从触发事件的节点到根节点上所有的 mark: 属性值;而 dataset 仅包含一个节点的 data- 属性值。
    细节注意事项:
    如果存在同名的 mark ,父节点的 mark 会被子节点覆盖。(同名时离源组件越近,级别越高)
    在自定义组件中接收事件时, mark 不包含自定义组件外的节点的 mark 。(当使用自定义组件时,自定义组件中的mark是独立的)
    不同于 dataset ,节点的 mark 不会做连字符和大小写转换。
    */
  mark:{}
  
  //自定义事件所携带的数据,如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息,详见组件定义中各个事件的定义。
    点击事件的detail 带有的 x, y 同 pageX, pageY 代表距离文档左上角的距离
  detail:{}

  //触发事件的源组件。
  target:{
      //事件源组件的ID
      id:"tapTest"
      //事件源组件上由data-开头的自定义属性组成的集合
      //可以绑定动态数据,如:data-
      /*
      dataset
      在组件节点中可以附加一些自定义数据。这样,在事件中可以获取这些自定义的节点数据,用于事件的逻辑处理。
      在 WXML 中,这些自定义数据以 data- 开头,多个单词由连字符 - 连接。这种写法中,连字符写法会转换成驼峰写法,而大写字符会自动转成小写字符。如:
      data-element-type ,最终会呈现为 event.currentTarget.dataset.elementType ;
      data-elementType ,最终会呈现为 event.currentTarget.dataset.elementtype 。
      //index.wxml
      <view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>
      //index.js
      Page({
        bindViewTap:function(event){
        console.log(event.currentTarget.dataset.alphaBeta === "1") // 会转为驼峰写法
        console.log(event.currentTarget.dataset.alphabeta === "2") // 大写会转为小写
        }
        })
      */
      dataset:{hi: "Hi WeChat"}
    }

    //touches 是一个数组,每个元素为一个 Touch 对象(canvas 触摸事件中携带的 touches 是 CanvasTouch 数组)。 表示当前停留在屏幕上的触摸点
  touches:[
    0:{
      //触摸点标识符
      identifier: 0
      //距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴
      clientX: 29
      clientY: 411
      force: 1
      //距离文档左上角的距离,文档的左上角为原点 ,横向为X轴,纵向为Y轴
      pageX: 29
      pageY: 517
      }
    ]

  //页面打开到触发事件所经过的毫秒数
  timeStamp:1000

  //事件绑定的当前组件
  currentTarget:{
      //当前组件ID(如冒泡事件,此值为当前组件ID非源组件)
      id: "tapTest"
      //当前组件上由data-开头的自定义属性组成的集合(当前组件属性)
      dataset: {hi: "Hi WeChat"}
    }

  //changedTouches 数据格式同 touches。 表示有变化的触摸点,如从无变有(touchstart),位置变化(touchmove),从有变无(touchend、touchcancel)
  changedTouches:[{}]

  __proto__: Object
  }
-->

  page.json

  每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项。文件内容为一个 JSON 对象

// 页面配置page.json
// 每一个小程序页面都可以使用 .json 文件来对本页面的窗口表现进行配置。页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项。文件内容为一个 JSON 对象,有以下属性
{
  // 导航栏背景颜色 颜色都以十六进制显示,否则在不同设备中可能显示错误
  "navigationBarBackgroundColor": "#13c106",
  // 导航栏标题颜色,仅支持 black / white    (黑/白)
  "navigationBarTextStyle": "black",
  // 导航栏标题文字内容
  "navigationBarTitleText": "聽風吟",
  // 导航栏样式,仅支持以下值:default 默认样式 、 custom 自定义导航栏,只保留右上角胶囊按钮
  "navigationStyle": "default",
  // 窗口的背景色
  "backgroundColor": "#13c106",
  // 下拉 loading 的样式,仅支持 dark (三个点)/ light    (无特殊展示)
  "backgroundTextStyle": "dark",
  // 顶部窗口的背景色,仅 iOS 支持
  "backgroundColorTop": "#13c106",
  // 底部窗口的背景色,仅 iOS 支持
  "backgroundColorBottom": "#13c106",
  // 控制当前页下拉刷新
  "enablePullDownRefresh": false,
  // 控制当前页上拉刷新
  "onReachBottomDistance": false,
  // 控制当前页屏幕旋转   支持 auto (自动)/ portrait(竖屏) / landscape (2.5.0支持固定横屏显示)
  "pageOrientation": "portrait",
  // 设置为 true 则页面整体不能上下滚动。只在页面配置中有效,无法在 app.json 中设置
  "disableScroll": true,
  // 页面自定义组件配置
  /*
  自定义组件
从小程序基础库版本 1.6.3 开始,小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。
开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似
  */
  /*
  // custom-comp
  创建自定义组件
类似于页面,一个自定义组件由 json wxml wxss js 4个文件组成。要编写一个自定义组件,首先需要在 json 文件中进行自定义组件声明(将 component 字段设为 true 可以将这一组文件设为自定义组件) 

// custom-comp.json
  {
    "component": true
  }

在 wxml 文件中编写组件模板,在 wxss 文件中加入组件样式,它们的写法与页面的写法类似。

// custom-comp.wxml
  <view class="inner">
    {{innerText}}
  </view>
  <slot></slot>

// custom-comp.wxss
  .inner {
    color: red;
  }
// 注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。

在自定义组件的 js 文件中,需要使用 Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法。
组件的属性值和内部数据将被用于组件 wxml 的渲染,其中,属性值是可由组件外部传入的
// custom-comp.js
  Component({
    properties: {
      // 这里定义了innerText属性,属性值可以在组件使用时指定
      innerText: {
        type: String,
        value: 'default value',
      }
    },
    data: {
      // 这里是一些组件内部数据
      someData: {}
    },
    methods: {
      // 这里是一个自定义方法
      customMethod: function(){}
    }
  })
  */

  // 使用自定义组件,使用已注册的自定义组件前,首先要在页面的 json 文件中进行引用声明。此时需要提供每个自定义组件的标签名和对应的自定义组件文件路径:
  "usingComponents": {
    "custom-comp": "./custom-comp"
  }
  /*
  <view>
    <!-- 以下是对一个自定义组件的引用 -->
    <custom-comp inner-text="Some text"></custom-comp>
  </view>
  */
  // 在页面的 wxml 中就可以像使用基础组件一样使用自定义组件。节点名即自定义组件的标签名,节点属性即传递给组件的属性值
  // 自定义组件的 wxml 节点结构在与数据结合之后,将被插入到引用位置内
  /*
  细节注意事项:
因为 WXML 节点标签名只能是小写字母、中划线和下划线的组合,所以自定义组件的标签名也只能包含这些字符。
自定义组件也是可以引用自定义组件的,引用方法类似于页面引用自定义组件的方式(使用 usingComponents 字段)。
自定义组件和页面所在项目根目录名不能以“wx-”为前缀,否则会报错。
注意,是否在页面文件中使用 usingComponents 会使得页面的 this 对象的原型稍有差异,包括:

  使用 usingComponents 页面的原型与不使用时不一致,即 Object.getPrototypeOf(this) 结果不同。
  使用 usingComponents 时会多一些方法,如 selectComponent 。
  出于性能考虑,使用 usingComponents 时, setData 内容不会被直接深复制,即 this.setData({ field: obj}) 后 this.data.field === obj 。(深复制会在这个值被组件间传递时发生。)
  */
}

3).项目配置 project.config.json

//工具配置project.config.json
//官方提供的配置非常残缺。。。
/*
如配置值为""则为Sring类型,根据相应路径或提示更改即可
如配置值为true则当前配置为Boolean类型
如配置值为Object固定选项则会有相应提示
*/
{
  //指定小程序源码的目录(需为相对路径)--
  "miniprogramRoot": "",
  //指定腾讯云项目的目录(需为相对路径)--
  "qcloudRoot": "",
  //指定插件项目的目录(需为相对路径)--
  "pluginRoot": "",
  //编译类型
  /*
  仅包含miniprogram (普通小程序项目)plugin(小程序插件项目)
  */
  "compileType": "miniprogram",
  //项目设置
  "setting": {
    //是否启用 es6 转 es5
    "es6": true,
    //上传代码时样式是否自动补全
    "postcss": true,
    //上传代码时是否自动压缩
    "minified": true,
    //是否检查安全域名和 TLS 版本
    "urlCheck": false,
    //是否进行代码保护--
    "uglifyFileName": true,
    //是否打开SiteMap索引提示((默认为true)
    /*
    微信现已开放小程序内搜索,开发者可以通过 sitemap.json 配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。 爬虫访问小程序内页面时,会携带特定的 user-agent:mpcrawler 及场景值:1129。需要注意的是,若小程序爬虫发现的页面数据和真实用户的呈现不一致,那么该页面将不会进入索引中。
    */
    /*
    说人话系列:
    微信小程序2019/03/29号推出 sitemap 功能,默认收录所有小程序页面功能,用于微信场景搜索,之后可以根据内容来搜索小程序,而不仅止于小程序名称和简介
    此功能并非关闭索引,而是关闭索引的提示
    关闭索引请查看 sitemap.json 
    */
    "checkSiteMap": true,
    //是否使用工具渲染 CoverView--
    "coverView": true,
    //是否打开增强编译--
    "enhance": true,
    //增强编译下Babel的配置项--
    "babelSetting": {
      //配置需要跳过Babel编译(包括代码压缩)处理的文件或目录
      "ignore": [],
      //暂无官方说明
      "disablePlugins": [],
      //Babel 辅助函数的输出目录,默认为 @babel/runtime
      "outputPath": ""
    },
    //上传时是否带上 sourcemap(默认为true)
    "uploadWithSourceMap": true,
    //暂无官方说明
    "newFeature": true,
    "autoAudits": false,
    "checkInvalidKey": true,
  },
  //基础库版本
  "libVersion": "2.8.0",
  //当前项目appid,只在新建项目时读取
  "appid": "wx03f53a71c3f1c05c",
  //当前项目名字,只在新建项目时读取
  "projectname": "XJTest",
  //打包配置项(此项设置需重启开发者工具才可生效)
  /*
  packOptions 用以配置项目在打包过程中的选项。打包是预览、上传时对项目进行的必须步骤。

目前可以指定 packOptions.ignore 字段,用以配置打包时对符合指定规则的文件或文件夹进行忽略,以跳过打包的过程,这些文件或文件夹将不会出现在预览或上传的结果内。

packOptions.ignore 为一对象数组,对象元素类型如下:
字段名    类型    说明
value    string    路径1或取值
type    string    类型
*/
  /*
type 可以取的值为 
folder(文件夹)
file(文件)
suffix(后缀)
prefix(前缀)
regexp2(正则表达式)
glob2(Glob 规则)

所有规则值都会自动忽略大小写。
注 1: value 字段的值若表示文件或文件夹路径,以小程序目录 (miniprogramRoot) 为根目录。
注 2: regexp、glob 仅 1.02.1809260 及以上版本工具支持。
*/
  //示例
  "packOptions": {
    "ignore": [
      {
        "type": "file",
        "value": "test/test.js"
      },
      {
        "type": "folder",
        "value": "test"
      },
      {
        "type": "suffix",
        "value": ".webp"
      },
      {
        "type": "prefix",
        "value": "test-"
      },
      {
        "type": "glob",
        "value": "test/**/*.js"
      },
      {
        "type": "regexp",
        "value": "\\.jsx$"
      }
    ]
  },
  //调试配置项
  /*
  debugOptions 用以配置在对项目代码进行调试时的选项。

目前可以指定 debugOptions.hidedInDevtools 字段,用以配置调试时于调试器 Sources 面板隐藏源代码的文件。

hidedInDevtools 的配置规则和 packOptions.ignore 是一致的。

当某个 js 文件符合此规则时,调试器 Sources 面板中此文件源代码正文内容将被隐藏,显示为:
// xxx.js has been hided by project.config.json

注:配置此规则后,可能需要关闭并重新打开项目才能看到效果。
*/
  "debugOptions": {
    "hidedInDevtools": [
      {
        "type": "file",
        "value": "test/test.js"
      },
      {
        "type": "folder",
        "value": "test"
      },
      {
        "type": "suffix",
        "value": ".webp"
      },
      {
        "type": "prefix",
        "value": "test-"
      },
      {
        "type": "glob",
        "value": "test/**/*.js"
      },
      {
        "type": "regexp",
        "value": "\\.jsx$"
      }
    ]
  },
  //自定义预处理
  "scripts": {
    //官方仅以下说明
    /*
    scripts 中指定自定义预处理的命令
    名字    说明
    beforeCompile    编译前预处理命令
    beforePreview    预览前预处理命令
    beforeUpload    上传前预处理命令
    */
  },
  //当前文件描述
  "description": "项目配置文件",
  //是否为游客
  "isGameTourist": false,
  //工具类型
  "simulatorType": "wechat",
  //开发者工具插件库版本
  "simulatorPluginLibVersion": {},
  //暂无官方说明
  "condition": {
    "search": {
      "current": -1,
      "list": []
    },
    "conversation": {
      "current": -1,
      "list": []
    },
    "game": {
      "currentL": -1,
      "list": []
    },
    "miniprogram": {
      "current": -1,
      "list": []
    }
  }
}

  4).小程序索引配置sitemap.json

//小程序索引配置sitemap.json
/*
微信现已开放小程序内搜索,开发者可以通过 sitemap.json 配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。 爬虫访问小程序内页面时,会携带特定的 user-agent:mpcrawler 及场景值:1129。需要注意的是,若小程序爬虫发现的页面数据和真实用户的呈现不一致,那么该页面将不会进入索引中。
*/
/*
注:如果没有 sitemap.json ,则默认为所有页面都允许被索引
注:{"action": "allow","page": "*"} 是优先级最低的默认规则,未显式指明 "disallow" 的都默认被索引
*/
{
  //文件描述
  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
  // 小程序索引配置
  "rules": [
    {
      // "allow"(允许)、"disallow"(不允许)    命中该规则的页面是否能被索引
      "action": "allow",
      // "*"  所有页面/页面的路径
      "page": "path/to/page",
      // 当 page 字段指定的页面在被本规则匹配时可能使用的页面参数名称的列表(不含参数值)
      "params": [
        "a",
        "b"
      ],
      // 当 page 字段指定的页面在被本规则匹配时,此参数说明 params 匹配方式
      /*
exact        当小程序页面的参数列表等于 params 时,规则命中
inclusive    当小程序页面的参数列表包含 params 时,规则命中
exclusive    当小程序页面的参数列表与 params 交集为空时,规则命中
partial      当小程序页面的参数列表与 params 交集不为空时,规则命中
  */
      "matching": "exact"
    },
    {
      "action": "disallow",
      "page": "path/to/page"
    }
  ]
  /*
path/to/page?a=1&b=2 => 优先索引
path/to/page => 不被索引
path/to/page?a=1 => 不被索引
path/to/page?a=1&b=2&c=3 => 不被索引
其他页面都会被索引
  */
}

  

  

二、框架

三、组件

四、API

require和import的区别

import和require都是被模块化所使用。

1-遵循规范

require 是 AMD规范引入方式

import是ES6的一个语法标准,如果要兼容浏览器的话必须转化成ES5的语法

2-调用时间

require是运行时调用,所以require理论上可以运用在代码的任何地方

import是编译时调用,所以必须放在文件开头

3-本质

require是赋值过程,其实require的结果就是对象、数字、字符串、函数等,再把require的结果赋值给某个变量

import是解构过程,但是目前所有的引擎都还没有实现import,我们在node中使用babel支持ES6,也仅仅是将ES6转码为ES5再执行,import语法会被转码为require

变量声明(var、let、const)

var:声明全局变量。换句话理解就是,声明在for循环中的变量,跳出for循环同样可以使用。

let:声明块级变量。即局部变量。(只在let命令所在的代码块内有效)

const:声明一个只读常量。具有块级作用域。(一旦声明即不可更改,声明时必须赋值)

不存在变量提升

var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。

为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

var tmp = 123;

if (true) {

tmp = 'abc'; // ReferenceError

let tmp;

}

上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。

ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

不允许重复声明

let不允许在相同作用域内,重复声明同一个变量

const本质

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,它指向的数据结构是可变的。

JSON

是一种取代XML的一种轻量级的数据交换格式

它独立于语言的文本格式的的同时还采用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)和xml相比,它更小巧、易于人阅读和编写,并且描述能力也不差,同时也易于机器解析和生成。

这些特性使JSON成为理想的数据交换语言,利于网络传输数据且节省流量而起到加快速度的作用。

书写格式是:以“{”开始,“}”结束。是一个无序的“‘名称/值’对”集合。名称写在前面(在双引号中),值对写在后面(同样在双引号中),中间用冒号隔开。

[如果是字符串,那不管是键或值最好都用双引号引起来]

-------------------函数记录-------------------

获取当前系统信息

wx.getSystemInfo({

success: function (res) {

console.log(res)

}

})

包含信息:

DKVersion:"2.7.7"        -SDK版本

batteryLevel:100         -电池水平

brand:"devtools"          -品牌

errMsg:"getSystemInfo:ok"     -errMsg

fontSizeSetting:16         -字体大小设置

language:"zh"           -语言

model:"iPhone 7 Plus"       -模型

pixelRatio:3           -像素比

platform:"devtools"        -平台

screenHeight:736       -屏幕高度

screenWidth:414         -屏幕宽度

statusBarHeight:20        -状态栏高度

system:"iOS 10.0.1"       -系统

version:"6.6.3"         -版本

windowHeight:672       -窗口高度

windowWidth:414        -窗口宽度