跳至内容
咸鱼笔记
用户工具
注册
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
注册
登录
>
最近更改
媒体管理器
网站地图
您在这里:
start
»
mina
»
2.小程序的代码构成
mina:code_composition
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 2.小程序的代码构成 ====== 一个小程序<wrap em>主体部分</wrap>由<wrap em>三个</wrap>文件组成,必须放在项目的<wrap em>根目录</wrap> \\ - app.js 小程序<wrap hi>逻辑</wrap> - app.json 小程序<wrap hi>公共配置</wrap> - app.wxss 小程序<wrap hi>公共样式表</wrap> :!: 没有app.wxml文件,小程序的首页是由app.json文件的"pages"字段配置。小程序所有的页面必须在app.json声明才可以。 文件类型说明: \\ - .json 后缀的 JSON 配置文件 \\ - .wxml 后缀的 WXML 模板文件 \\ - .wxss 后缀的 WXSS 样式文件 \\ - .js 后缀的 JS 脚本逻辑文件 \\ ===== -#1 JSON 配置 ===== JSON 是一种<wrap hi>数据格式</wrap>,在小程序中,JSON扮演的<wrap em>静态配置</wrap>的角色。小程序是<wrap hi>无法</wrap>在运行过程中去动态<wrap hi>更新</wrap>JSON 配置文件从而发生对应的变化的。 \\ JSON文件都是被包裹在一个<wrap em>大括号</wrap>中 {},通过key-value的方式来表达数据。JSON的Key必须包裹在一个<wrap hi>双引号</wrap>中。:!: 无法使用注释,试图添加注释将会引发报错。\\ <wrap hi>值只能是以下几种数据格式</wrap> \\ * 数字,包含浮点数和整数 * 字符串,需要包裹在双引号中 * Bool值,true 或者 false * 数组,需要包裹在方括号中 [] * 对象,需要包裹在大括号中 {} * Null {{ :微信小程序:json.png?400 |}} ==== - app.json ==== 全局配置:包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。[[https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/code.html#JSON-配置|[官方文档]JSON-配置]] \\ <code> { "pages":[ "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" } } </code> <wrap em> pages</wrap> 接受一个数组(<wrap em>使用中括号[]</wrap>),每一项都是字符串(<wrap em>双引号</wrap>),来指定小程序由哪些页面组成。每一项代表对应页面的【路径+文件名】信息,<wrap em>数组的第一项代表小程序的初始页面</wrap>。:!: 小程序中新增/减少页面,都需要对 pages 数组进行修改。\\ <wrap em>window</wrap>用于设置小程序的状态栏、导航条、标题、窗口背景色。[[https://www.w3cschool.cn/weixinapp/hw9k1q8m.html|[w3cschool]小程序配置]]\\ ==== - project.config.json ==== 工具配置 :工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就<wrap em>自动会帮你恢复到当时你开发项目时的个性化配置</wrap>,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。[[https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html|开发者工具的配置]] \\ ==== - page.json ==== 页面配置:用来表示 pages/logs 目录下的 logs.json 这类<wrap em>和小程序页面相关</wrap>的配置。 \\ 可能你小程序里边的每个页面都有不一样的色调来区分不同功能模块,因此提供了 page.json,让开发者可以独立定义每个页面的一些属性。 [[https://developers.weixin.qq.com/miniprogram/dev/framework/config.html#页面配置|页面配置]]\\ :!: page.json中配置项会覆盖 app.json 的 window 中相同的配置项 \\ page.json<wrap em>只能设置window相关</wrap>的配置项,以决定本页面的窗口表现,所以无需写window这个键。[[https://www.w3cschool.cn/weixinapp/hw9k1q8m.html|小程序配置]] \\ <code> { "navigationBarBackgroundColor": "#ffffff", "navigationBarTextStyle": "black", "navigationBarTitleText": "微信接口功能演示", "backgroundColor": "#eeeeee", "backgroundTextStyle": "light" } </code> ===== -#2 WXML 模板 ===== WXML由标签、属性等等构成,充当的就是类似 HTML 的角色。不同之处 \\ - 小程序的 WXML 用的标签是 view, button, text 等等[[https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/framework.html|小程序的能力]] - 多了一些'' wx:if'' 这样的属性以及'' { { } }'' 这样的表达式 <code xml> <view class="container"> <view class="userinfo"> <button wx:if="{{!hasUserInfo && canIUse}}"> 获取头像昵称 </button> <block wx:else> <image src="{{userInfo.avatarUrl}}" background-size="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </block> </view> <view class="usermotto"> <text class="user-motto">{{motto}}</text> </view> </view> </code> 小程序采用MVVM的开发模式,提倡把<wrap hi>渲染</wrap>和<wrap hi>逻辑</wrap>分离。简单来说就是不要再让JS直接操控DOM,JS只需要管理状态即可,然后再通过一种<wrap hi>模板语法</wrap>来描述状态和界面结构的关系即可。 \\ wxml这么写 \\ <code xml> <text>{{ msg }}</text> </code> JS 只需要管理状态即可: \\ <code javascript>this.setData({ msg: "Hello World" })</code> ==== - 数据绑定 ==== 通过''{{}}''的语法把一个<wrap hi>变量</wrap>绑定到界面上,我们称为<wrap hi>数据绑定</wrap>。 \\ 更多绑定参考[[https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/data.html|微信小程序 数据绑定]] \\ === - 内容绑定 === <code xml> <!--wxml--> <text>{{message}}</text> </code> <code javascript> // page.js Page({ data: { message: 'Hello MINA!' } }) </code> === - 组件属性 === (需要在双引号之内) <code xml> <view id="item-{{id}}"> </view> </code> <code javascript> Page({ data: { id: 0 } }) </code> === - 控制属性 === (需要在双引号之内) <code xml> <view wx:if="{{condition}}"> </view> </code> <code javascript> Page({ data: { condition: true } }) </code> === - 数据路径运算 === <code xml> <view>{{object.key}} {{array[0]}}</view> </code> <code javascript> Page({ data: { object: { key: 'Hello ' }, array: ['MINA'] } }) </code> 也可以用扩展运算符...来将一个对象展开 \\ <code xml> <template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template> </code> <code javascript> Page({ data: { obj1: { a: 1, b: 2 }, obj2: { c: 3, d: 4 } } }) </code> {a: 1, b: 2, c: 3, d: 4, e: 5} 仅仅通过数据绑定还不够完整的描述状态和界面的关系,还需要 if/else, for等控制能力,在小程序里边,这些控制能力都用 wx: 开头的属性来表达。[[https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/|WXML]] \\ === - 双向绑定语法 === <code xml> <input value="{{value}}" /> </code> 如果使用 this.setData({ value: 'leaf' }) 来更新 value ,this.data.value 和输入框的中显示的值都会被更新为 leaf ;但如果用户修改了输入框里的值,却不会同时改变 this.data.value 。 如果需要在用户输入的同时改变 this.data.value ,需要借助简易双向绑定机制。此时,可以在对应项目之前加入 model: 前缀 <code xml> <input model:value="{{value}}" /> </code> 双向绑定的表达式有如下限制: 只能是一个<wrap hi>单一字段</wrap>的绑定 ==== - 列表渲染 ==== === - wx:for === 在组件 view 上使用 wx:for <wrap em>控制属性</wrap>绑定一个<wrap em>数组</wrap>,即可使用数组中各项的数据<wrap em>重复渲染</wrap>该组件。[[https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/list.html|[官方文档 列表渲染]]] \\ :!: 默认数组的当前项的<wrap hi>下标变量名</wrap>默认为 index,数组当前<wrap hi>项的变量名</wrap>默认为 item \\ <code xml> <view wx:for="{{array}}"> {{index}}: {{item.message}} </view> </code> <code javascript> Page({ data: { array: [{ message: 'foo', }, { message: 'bar' }] } }) </code> 输出: \\ 0:foo 1:bar 使用 wx:for-item 可以指定数组当前元素的变量名, \\ 使用 wx:for-index 可以指定数组当前下标的变量名:\\ <code xml> <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"> {{idx}}: {{itemName.message}} </view> </code> 输出: \\ 0:foo 1:bar :!: 当 wx:for 的值为字符串时,会将字符串解析成字符串数组 \\ <code xml> <view wx:for="array"> {{item}} </view> </code> 等同于 \\ <code xml> <view wx:for="{{['a','r','r','a','y']}}"> {{item}} </view> </code> === - wx:key === 如果列表中项目的<wrap em>位置</wrap>会<wrap em>动态改变</wrap>或者有<wrap em>新的项目添加到列表</wrap>中,并且希望列表中的项目<wrap em>保持自己的特征和状态</wrap>(如 <input/> 中的输入内容,<switch/> 的选中状态),需要使用 wx:key 来<wrap em>指定列表中项目的唯一的标识符</wrap>。 \\ wx:key 的值以两种形式提供 \\ * 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。 * 保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个 :!: 唯一的字符串或者数字,如: 当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,<wrap em>框架会确保他们被重新排序,而不是重新创建</wrap>,以确保使组件保持自身的状态,并且提高列表渲染时的效率。 <code xml> <switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch> <button bindtap="switch"> Switch </button> <button bindtap="addToFront"> Add to the front </button> <switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch> <button bindtap="addNumberToFront"> Add to the front </button> </code> <code javascript> Page({ data: { 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'}, ], numberArray: [1, 2, 3, 4] }, 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 }) }, addToFront: function(e) { const length = this.data.objectArray.length this.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray) this.setData({ objectArray: this.data.objectArray }) }, addNumberToFront: function(e){ this.data.numberArray = [ this.data.numberArray.length + 1 ].concat(this.data.numberArray) this.setData({ numberArray: this.data.numberArray }) } }) </code> {{ :微信小程序:wxkey.png?400 |}} [[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/random|Math.random()]] 函数返回一个浮点, 伪随机数在范围从0到小于1 \\ [[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/floor|Math.floor()]] 返回小于或等于一个给定数字的最大整数。 \\ [[https://www.w3school.com.cn/js/jsref_concat_array.asp|concat()]] 方法用于连接两个或多个数组,该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。 \\ ==== - 条件渲染 ==== === - wx:if === 在框架中,我们用 '' wx:if="{ {condition} }" ''来判断是<wrap em>否需要渲染</wrap>该代码块:[[https://www.w3cschool.cn/weixinapp/weixinapp-conditional.html|微信小程序 条件渲染 wx:if]] \\ <code xml> <view wx:if="{{condition}}"> True </view> </code> 也可以用'' wx:elif ''和'' wx:else''来添加一个else块: \\ <code xml> <view wx:if="{{length > 5}}"> 1 </view> <view wx:elif="{{length > 2}}"> 2 </view> <view wx:else> 3 </view> </code> === - block wx:if === 因为''wx:if''是一个控制属性,需要将它添加到一个标签上。 \\ 但是<wrap em>如果我们想一次性判断多个组件标签</wrap>,我们可以使用一个'' block/ '' 标签将多个组件包装起来,并在上边使用''wx:if''控制属性。 \\ <code xml> <block wx:if="{{true}}"> <view> view1 </view> <view> view2 </view> </block> </code> ===== - WXSS 样式 ===== WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改。[[https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxss.html|WXSS]] \\ - app.wxss 作为全局样式,会作用于当前小程序的所有页面 \\ - 局部页面样式 page.wxss 仅对当前页面生效。 \\ ==== - 样式导入 ==== <code css> /** common.wxss 局部样式 **/ .small-p { padding:5px; } </code> :!:使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的<wrap em>相对路径</wrap>,用;表示语句结束。 <code css> /** app.wxss 全局样式**/ @import "common.wxss"; .middle-p { padding:15px; } </code> ==== - 内联样式 ==== *style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。 <code xml> <view style="color:{{color}};" /> </code> *class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。 <code xml> <view class="normal_view" /> </code> ===== - JS 逻辑交互(事件) ===== 用户做交互:响应用户的点击、获取用户的位置等等。在小程序里边,我们就通过编写 JS 脚本文件来处理用户的操作。 ==== - 代码案例 ==== 编写 JS 脚本文件来<wrap em>处理用户的操作</wrap>。[[https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html|WXML - 事件]] \\ <code xml> <!--app.wxml--> <view>{ { msg } }</view> <button bindtap="clickMe">点击我</button> </code> 点击 button 按钮的时候,我们希望把界面上 msg 显示成 "Hello World",于是我们在 button 上声明一个属性: bindtap ,在 JS 文件里边声明了 clickMe 方法来响应这次点击操作: \\ <code javascript> //app.js Page({ clickMe: function() { this.setData({ msg: "Hello World" }) } }) </code> ==== - 什么是事件 ==== [[https://www.w3cschool.cn/weixinapp/weixinapp-event.html|微信小程序 事件]] \\ * 事件是视图层到逻辑层的通讯方式。 * 事件可以将用户的行为反馈到逻辑层进行处理。 * 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。 * 事件对象可以携带额外信息,如id, dataset, touches。 在组件中绑定一个事件处理函数。\\ 如''bindtap'',当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。 \\ <code xml> <!--index.wxml--> <view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view> </code> <code javascript> //与index.wxml文件同目录下index.js,参数是event。 Page({ tapName: function(event) { console.log(event) } }) </code> ''console.log(event)''打印数据 <code javascript> { "type": "tap", "timeStamp":895, "target": { "id": "tapTest", "dataset": { "hi": "WeChat" } }, "currentTarget": { "id": "tapTest", "dataset": { "hi": "WeChat" } }, "detail": { "x":53, "y":14 }, "touches": [{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14, }], "changedTouches": [{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14, }], } </code> ==== - 事件分类 ==== 事件分为冒泡事件和非冒泡事件 \\ * 冒泡事件:当一个组件上的事件被触发后,该事件<wrap hi>会</wrap>向父节点传递。 * 非冒泡事件:当一个组件上的事件被触发后,该事件<wrap hi>不会</wrap>向父节点传递。 WXML的冒泡事件列表:\\ ^ 类型 ^ 触发条件 ^ | touchstart | 手指触摸动作开始 | | touchmove | 手指触摸后移动 | | touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 | | touchend | 手指触摸动作结束 | | tap | 手指触摸后马上离开 | | longtap | 手指触摸后,超过350ms再离开 | 注:除上表之外的其他组件自定义事件都是非冒泡事件,如[[https://www.w3cschool.cn/weixinapp/m8x71q8z.html|<form/>]]的submit事件,[[https://www.w3cschool.cn/weixinapp/3glu1q92.html|<input/>]]的input事件,<scroll-view/>的scroll事件,(详见各个[[https://www.w3cschool.cn/weixinapp/itz51q8o.html|组件]]) ==== - 事件绑定 ==== 事件绑定的写法同组件的属性,以key、value的形式。\\ * key以<wrap hi>bind</wrap>或<wrap hi>catch</wrap>开头,然后跟上事件的类型,如bind<wrap hi>tap</wrap>, catch<wrap hi>touchstart</wrap> * value是一个字符串,需要在对应的Page中定义同名的函数。不然当触发事件的时候会报错。 :!: ''bind''事件绑定不会阻止冒泡事件向上冒泡,''catch''事件绑定可以阻止冒泡事件向上冒泡。 \\ <code xml> <view id="outter" bindtap="handleTap1"> outer view <view id="middle" catchtap="handleTap2"> middle view <view id="inner" bindtap="handleTap3"> inner view </view> </view> </view> </code> 如在上边这个例子中,点击inner view会先后触发handleTap3和handleTap2(因为tap事件会冒泡到middle view,而middle view阻止了tap事件冒泡,不再向父节点传递),点击middle view会触发handleTap2,点击outter view会触发handleTap1。 :!: mut-bind 来绑定事件。一个 mut-bind 触发后,如果事件冒泡到其他节点上,其他节点上的 mut-bind 绑定函数不会被触发,但 bind 绑定函数和 catch 绑定函数依旧会被触发。 ==== - 数据绑定 ==== <code javascript> <view bindtap="{{ handlerName }}"> Click here! </view> </code> * 此时,页面的 this.data.handlerName 必须是一个字符串,指定事件处理函数名; * 如果它是个空字符串,则这个绑定会失效。 ==== - 事件的捕获阶段 ==== 捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。 可以采用''capture-bind''、''capture-catch''关键字,后者将中断捕获阶段和取消冒泡阶段。 在下面的代码中,点击 inner view 会先后调用handleTap2、handleTap4、handleTap3、handleTap1。 <code xml> <view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2"> outer view <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4"> inner view </view> </view> </code> ==== - 事件对象 ==== 如无特殊说明,当组件触发事件时,逻辑层绑定该事件的<wrap hi>处理函数</wrap>会收到一个<wrap hi>事件对象</wrap>。 \\ === BaseEvent基础事件对象属性列表 === ^ 属性 | 类型 ^ 说明 ^ | type | String | 事件类型 | | timeStamp | Integer | 事件生成时的**时间戳** | | target | Object | 触发事件的组件的一些**属性值集合** | | currentTarget | Object | **当前组件**的一些**属性值集合** | target 触发事件的源组件。 \\ ^ 属性 | 类型 ^ 说明 ^ | id | String | 事件源组件的id | | tagName | String | 当前组件的类型 | | dataset | Object | 事件源组件上由data-开头的自定义属性组成的集合 | currentTarget 事件绑定的当前组件。 \\ ^ 属性 | 类型 ^ 说明 ^ | id | String | 当前组件的id | | tagName | String | 当前组件的类型 | | dataset | Object | 事件源组件上由data-开头的自定义属性组成的集合 | 说明: target 和 currentTarget 可以参考上例中,点击 inner view 时,handleTap3 收到的事件对象 target 和 currentTarget 都是 inner,而 handleTap2 收到的事件对象 target 就是 inner,currentTarget 就是 middle。 dataset \\ 在组件中可以<wrap hi>定义数据</wrap>,这些数据将会通过事件<wrap hi>传递给 SERVICE</wrap>。书写方式:<wrap em>以data-开头</wrap>,多个单词由连字符-链接,不能有大写(大写会自动转成小写)如data-element-type,最终在 event.target.dataset 中会将连字符转成驼峰elementType。 \\ <code xml> <view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view> </code> <code javascript> Page({ bindViewTap:function(event){ event.target.dataset.alphaBeta === 1 // - 会转为驼峰写法 event.target.dataset.alphabeta === 2 // 大写会转为小写 } }) </code> === CustomEvent 自定义事件对象属性列表(继承 BaseEvent) === ^ 属性 | 类型 ^ 说明 ^ | detail | Object | 额外的信息 | detail \\ <wrap em>自定义事件所携带的数据</wrap>,如表单组件的提交事件会携带<wrap em>用户的输入</wrap>,媒体的错误事件会携带错误信息,详见[[https://www.w3cschool.cn/weixinapp/itz51q8o.html|组件]]定义中各个事件的定义。\\ 点击事件的detail 带有的 x, y 同 pageX, pageY 代表距离文档左上角的距离。\\ === TouchEvent 触摸事件对象属性列表(继承 BaseEvent) === ^ 属性 | 类型 ^ 说明 ^ | touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 | | changedTouches | Object | 触摸事件,当前变化的触摸点信息的数组 | ===== - sitemap 配置 ===== 小程序根目录下的 sitemap.json 文件用来配置小程序及其页面是否允许被微信索引。[[https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html|[官方文档]sitemap 配置]] <code> //所有页面都会被微信索引(默认情况) { "rules":[{ "action": "allow", //允许 "page": "*" }] } </code> <code> //配置 path/to/page 页面被索引,其余页面不被索引 { { "rules":[{ "action": "allow", //允许 "page": "path/to/page" }, { "action": "disallow",//不允许 "page": "*" }] } } </code>
mina/code_composition.txt
· 最后更改: 2020/08/24 22:40 (外部编辑)
页面工具
显示页面
过去修订
反向链接
回到顶部