微信小程序

微信小程序 框架(MINA)

小程序开发框架的目标是通过尽可能简单、高效的方式让开发者可以在微信中开发具有原生APP体验的服务。

框架提供了自己的视图层描述语言WXML和WXSS,以及基于JavaScript的逻辑层框架,并在视图层与逻辑层间提供了数据传输和事件系统,可以让开发者可以方便的聚焦于数据与逻辑上。

主体文件

在每个小程序框架中最关键也是必不可少的文件就是 app.js、app.json、app.wxss 这三个。其中,.js后缀的是脚本文件,.json后缀的文件是配置文件,.wxss后缀的是样式表文件。微信小程序会读取这些文件,并生成小程序实例。

app.js是小程序的脚本代码。我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量。调用框架提供的丰富的 API,如本例的同步存储及同步读取本地数据。

//app.js
App({
  onLaunch: function () {
    //调用API从本地缓存中获取数据
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)
  },
  getUserInfo:function(cb){
    var that = this;
    if(this.globalData.userInfo){
      typeof cb == "function" && cb(this.globalData.userInfo)
    }else{
      //调用登录接口
      wx.login({
        success: function () {
          wx.getUserInfo({
            success: function (res) {
              that.globalData.userInfo = res.userInfo;
              typeof cb == "function" && cb(that.globalData.userInfo)
            }
          })
        }
      });
    }
  },
  globalData:{
    userInfo:null
  }
})

app.json 是对整个小程序的全局配置。我们可以在这个文件中配置小程序是由哪些页面组成,配置小程序的窗口背景色,配置导航条样式,配置默认标题。注意该文件不可添加任何注释。

app.json 配置项列表

 

属性类型必填描述
pagesString Array设置页面路径
windowObject设置默认页面的窗口表现
tabBarObject设置底部 tab 的表现
networkTimeoutObject设置网络超时时间
debugBoolean设置是否开启 debug 模式

以下是一个包含了所有配置选项的简单配置app.json :

{
  "pages": [
    "pages/index/index",
    "pages/logs/index"
  ],  
"window": {
    "navigationBarTitleText": "Demo"
  },
  "tabBar": {
    "list": [{
      "pagePath": "pages/index/index",
      "text": "首页"
    }, {
      "pagePath": "pages/logs/logs",
      "text": "日志"
    }]
  },
  "networkTimeout": {
    "request": 10000,
    "downloadFile": 10000
  },
  "debug": true
}

app.wxss 是整个小程序的公共样式表。我们可以在页面组件的 class 属性上直接使用 app.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;
}

响应式的数据绑定

框架的核心是一个响应的数据绑定系统。

整个系统分为两块视图层(View)和逻辑层(App Service)。

框架可以让数据与视图非常简单地保持同步。当做数据修改的时候,只需要在逻辑层修改数据,视图层就会做相应的更新。

 

MINA 文件结构

MINA程序包含一个描述整体程序的app和多个描述各自页面的page。一个MINA程序主体部分由三个文件组成,必须放在项目的根目录,如下:

文件必需作用
app.js小程序逻辑
app.json小程序公共设置
app.wxss小程序公共样式表

一个MINA页面由四个文件组成,分别是:

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

 

逻辑层(App Service)

小程序开发框架的逻辑层是由JavaScript编写。逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。


注册程序 App()函数

App()函数用来注册一个小程序。接受一个object参数,其指定小程序的生命周期函数等。

object参数说明:

属性类型描述触发时机
onLaunchFunction生命周期函数--监听小程序初始化当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
onShowFunction生命周期函数--监听小程序显示当小程序启动,或从后台运行进入前台显示,会触发 onShow
onHideFunction生命周期函数--监听小程序隐藏当小程序从前台进入后台,会触发 onHide
onErrorFunction错误监听函数当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
onPageNotFoundFunction页面不存在监听函数当小程序出现要打开的页面不存在的情况,会带上页面信息回调该函数,详见下文
其他Any 开发者可以添加任意的函数或数据到 Object 参数中,用 this 可以访问

示例代码:

App({
  onLaunch: function(options) { 
    // Do something initial when launch.
  },
  onShow: function(options) {
      // Do something when show.
  },
  onHide: function() {
      // Do something when hide.
  },
  onError: function(msg) {
    console.log(msg)
  },
  globalData: 'I am global data'
})

getApp()

我们提供了全局的getApp()函数,可以获取到小程序实例。

// other.js
var appInstance = getApp()
console.log(appInstance.globalData) // I am global data

注意:

App() 必须在app.js中注册,且不能注册多个。

不要在定义于App() 内的函数中调用getApp() ,使用this就可以拿到app实例。

不要在onLaunch的时候调用getCurrentPage(),此时page还没有生成。

getApp()通过获取实例之后,不要私自调用生命周期函数。


注册页面 Page()函数

Page() 函数用来注册一个页面。接受一个 object 参数,其指定页面的初始数据、生命周期函数、事件处理函数等。

示例代码:

//index.js
Page({
  data: { // 页面的初始数据
    text: 'init data',
    array: [{msg: '1'}, {msg: '2'}]
  },
  // 生命周期函数
  onLoad: function(options) { // 生命周期函数--监听页面加载
    // 一个页面只会调用一次,可以在 onLoad 中获取打开当前页面所调用的 query 参数。
  },
  onReady: function() { // 生命周期函数--监听页面初次渲染完成
    // 一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
  },
  onShow: function() { // 生命周期函数--监听页面显示
    // 每次打开页面都会调用一次。
  },
  onHide: function() { // 生命周期函数--监听页面隐藏
    // 当navigateTo或底部tab切换时调用。
  },
  onUnload: function() { // 生命周期函数--监听页面卸载
    // 当redirectTo或navigateBack的时候调用。
  },
  // 页面相关事件处理函数
  onPullDownRefresh: function() { // 监听用户下拉动作
    // 监听用户下拉刷新事件。
    // 需要在config的window选项中开启enablePullDownRefresh。
    // 当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。
  },
  onReachBottom: function() { // 页面上拉触底事件的处理函数
    // 监听用户下拉触底事件。
  },
  onPageScroll: function() { // 页面滚动触发事件的处理函数
    // 监听用户滑动页面事件。
  },
  onShareAppMessage: function () { // 用户点击右上角转发
   // 只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮。
   // 用户点击转发按钮的时候会调用。
   // 此事件需要 return 一个 Object,用于自定义转发内容。
   return {
      title: '自定义转发标题',
      path: '/page/user?id=123'
    } 
  },
  // 事件处理函数。
  // 在渲染层可以在组件中加入事件绑定,当达到触发事件时,就会执行 Page 中定义的事件处理函数。
  viewTap: function() {
    this.setData({
      text: 'Set some data for updating view.'
    })
  }
})

Page.prototype.route

route 字段可以获取到当前页面的路径。

Page.prototype.setData()

setData 函数用于将数据从逻辑层发送到视图层,同时改变对应的 this.data 的值。

 

微信小程序 模块化

文件作用域

在JavaScript文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。
通过全局函数getApp()可以获取全局的应用实例,如果需要全局的数据可以在App()中设置,如:

// app.js
App({
  globalData: 1
})
// b.jsa.js.
var localValue = 'b'
console.log(getApp().globalData)

模块化

exports是module.exports的一个引用,因此在模块里边随意更改exports的指向会造成未知的错误。所以我们更推荐开发者采用module.exports来暴露模块接口,除非你已经清晰知道这两者的关系。

// common.js
function sayHello(name) {
  console.log('Hello ${name} !')
}
function sayGoodbye(name) {
  console.log('Goodbye ${name} !')
}
module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye

在需要使用这些模块的文件中,使用require(path)将公共代码引入(require暂时不支持绝对路径)。

var common = require('common.js')
Page({
  helloMINA: function() {
    common.sayHello('MINA')
  }
  goodbyeMINA: function() {
    common.sayGoodbye('MINA')
  }
})

 

视图层(View) - WXML

MINA的视图层由WXML与WXSS编写。

将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层。

WXML(WeiXin Markup language)用于描述页面的结构。

WXSS(WeiXin Style Sheet)用于描述页面的样式。

组件(Component)是视图的基本组成单元。

WXML

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

 

数据绑定

WXML中的动态数据均来自对应Page的data。

内容

<view> {{ message }} </view>
Page({
  data: {
    message: 'Hello MINA!'
  }
})

组件属性(需要在双引号之内)

<view id="item-{{id}}"> </view>
Page({
  data: {
    id: 0
  }
})

控制属性(需要在双引号之内)

<view wx:if="{{condition}}"> </view>
Page({
  data: {
    condition: true
  }
})

关键字(需要在双引号之内)

<checkbox checked="{{false}}"> </checkbox>

特别注意:不要直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值。

运算

可以在 {{}} 内进行简单的运算,支持的有如下几种方式:

三元运算:

<view hidden="{{flag ? true : false}}"> Hidden </view>

算数运算:

<view> {{a + b}} + {{c}} + d </view>

数据路径运算:

<view>{{object.key}} {{array[0]}}</view>

 

列表渲染 wx:for

在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。
使用 wx:for-item 可以指定数组当前元素的变量名。
使用 wx:for-index 可以指定数组当前下标的变量名。

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName" wx:key="unique">
  {{idx}}: {{itemName.message}}
</view>

wx:key

如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/> 中的输入内容,<switch/> 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

注意:

当 wx:for 的值为字符串时,会将字符串解析成字符串数组

<view wx:for="array">
  {{item}}
</view>

等同于

<view wx:for="{{['a','r','r','a','y']}}">
  {{item}}
</view>

 

条件渲染 wx:if

在框架中,我们用wx:if="{{condition}}"来判断是否需要渲染该代码块,也可以用wx:elif和wx:else来添加一个else块:

<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>

 

模板(template)

WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。

定义模板

使用name属性,作为模板的名字。然后在<template/>内定义代码片段,如:

<template name="msgItem">
  <view>
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template>

使用模板

使用is属性,声明需要的使用的模板,然后将模板所需要的data传入,如:

<template is="msgItem" data="{{...item}}"/>

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>

模板的作用域

模板拥有自己的作用域,只能使用data传入的数据。

 

事件

事件是视图层到逻辑层的通讯方式。

事件可以将用户的行为反馈到逻辑层进行处理。

事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。

事件对象可以携带额外信息,如id, dataset, touches。

事件的使用方式

  • 在组件中绑定一个事件处理函数。

如 bindtap,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。

<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>
  • 在相应的Page定义中写上相应的事件处理函数,参数是event。
Page({
  tapName: function(event) {
    console.log(event)
  }
})

事件分类

事件分为冒泡事件和非冒泡事件

  1. 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
  2. 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。

WXML的冒泡事件列表:

类型触发条件
touchstart手指触摸动作开始
touchmove手指触摸后移动
touchcancel手指触摸动作被打断,如来电提醒,弹窗
touchend手指触摸动作结束
tap手指触摸后马上离开
longtap手指触摸后,超过350ms再离开

事件绑定

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

key以bind或catch开头,然后跟上事件的类型,如bindtap, catchtouchstart。

value是一个字符串,需要在对应的Page中定义同名的函数。不然当触发事件的时候会报错。

bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。

<view id="outter" bindtap="handleTap1">
  outer view
  <view id="middle" catchtap="handleTap2">
    middle view
    <view id="inner" bindtap="handleTap3">
      inner view
    </view>
  </view>
</view>

事件对象

如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象。

function(e){
   console.log(e.target);
   console.log(e.detail);
}

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

属性类型说明
typeString事件类型
timeStampInteger该页面打开到触发事件所经过的毫秒数。
targetObject触发事件的根源组件的一些属性值集合,包括触发事件组件的id,类型,以及dataset自定义属性的集合
currentTargetObject触发事件的当前组件,触发当前事件组件的id,类型,以及dataset自定义属性的集合

CustomEvent 自定义事件对象属性列表(继承 BaseEvent):

属性类型说明
detailObject自定义事件所携带的数据,如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息

target

触发事件的源组件。

属性类型说明
idString事件源组件的id
tagNameString当前组件的类型
datasetObject事件源组件上由data-开头的自定义属性组成的集合

currentTarget

事件绑定的当前组件。

属性类型说明
idString当前组件的id
tagNameString当前组件的类型
datasetObject当前组件上由data-开头的自定义属性组成的集合

dataset

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

 

引用

WXML提供两种文件引用方式import和include。

import

import可以在该文件中使用目标文件定义的template,如在item.wxml中定义了一个叫item的template:

<!-- item.wxml -->
<template name="item">
  <text>{{text}}</text>
</template>

在index.wxml中引用了item.wxml,就可以使用item模板:

<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>

import的作用域

import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。

include

include可以将目标文件除了<template/>的整个代码引入,相当于是拷贝到include位置,如:

<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>

 

视图层(View) - WXS

在微信小程序开发中,是不能直接在wxml中写js代码的,因此就有了wxs。

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

WXS 代码可以编写在 wxml 文件中的 <wxs> 标签内,或以 .wxs 为后缀名的文件内。

注意:

  • <template> 标签中,只能使用定义该 <template> 的 WXML 文件中定义的 <wxs> 模块
  • 切记wxs里面的变量不要使用let,因为wxs是微信的脚本语言,和js还是有区别的

模块

每一个 .wxs 文件和 <wxs> 标签都是一个单独的模块。

每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。

每个 wxs 模块均有一个内置的 module 对象,通过该属性,可以对外共享本模块的私有变量与函数,这样就可以被别的wxs文件或<wxs>标签引入。

内嵌wxs脚本:

wxs代码可编写在wxml文件中,<wxs></wxs>标签内,就像JavaScript代码可以编写在html文件中的<script></script>标签内一样。

wxml文件中的每个<wxs></wxs>标签,必须提供一个module属性,用来指定当前<wxs></wxs>标签的模块名。在单个wxml文件内,建议其值唯一。

<!-- wxml --> 
<wxs module="localFilter">
  var some_msg = "hello world";
  function fnFirstText(text) {
    if (null != text && text.length > 1) {
      return text.substring(0, 1);
    } else {
      return text;
    }
  }

  module.exports = {
    msg : some_msg,
    fnFirstText: fnFirstText
  }
</wxs>

在wxml中引入内联的wxs脚本: 

<text>{{localFilter.fnFirstText(businessName)}}</text>
<text>{{localFilter.msg}}</text>

外联wxs脚本:

wxs代码可以编写在以.wxs为后缀的文件内,就像js一样可以编写在.js文件中一样。

// /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";

在wxml中引入外联的wxs脚本: 

<!--wxml--> 
<wxs src="../../filter/filter.wxs" module="tools" />
<view> {{tools.msg}} </view>
<view> {{tools.FOO}} </view> 
<view> {{tools.bar(tools.FOO)}} </view> 

 require 函数

在.wxs模块中引用其他 wxs 文件模块,可以使用 require 函数。

引用的时候,要注意如下几点:

  • 只能引用 .wxs 文件模块,且必须使用相对路径。
  • wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 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";
// /pages/logic.wxs
var tools = require("./tools.wxs");

console.log(tools.FOO);
console.log(tools.bar("logic.wxs"));
console.log(tools.msg);

 

WXSS

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

WXSS用来决定WXML的组件应该怎么显示。

样式导入

使用@import语句可以导入外联样式表,@import跟需要导入的外联样式表的相对路径,用;表示语句结束。

示例代码:

/** common.wxss **/
.small-p{
  padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
  padding:15px;
}

内联样式

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

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

全局样式与局部样式

定义在app.wxss中的样式为全局样式,作用于每一个页面。在page的wxss文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖app.wxss中相同的选择器。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mephisto180502

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值