荷塘映月 發表於 2022-2-13 11:28:00

微信小程序开发基础篇

<h1 id="微信小程序开发基础篇">微信小程序开发基础篇</h1>
<h1 id="一初识微信小程序">一、初识微信小程序</h1>
<h2 id="1什么是微信小程序">1、什么是微信小程序</h2>
<h3 id="ⅰ-小程序历史">Ⅰ-小程序历史</h3>
<blockquote>
<ol>
<li>2017 年度百度百科十大热词之一</li>
<li>微信小程序,简称小程序,英文名 Mini Program,是一种不需要下载安装即可使用的应用 (<code>张小龙对其的定义是无需安装,用完即走,实际上是需要安装的,只不过小程序的体积特别小,下载速度很快,用户感觉不到下载的过程</code> )</li>
<li>小程序刚发布的时候要求压缩包的体积不能大于 1M,,否则无法通过,在2017年4月做了改进,由原来的1M提升到2M;</li>
<li>2017年1月9日0点,万众瞩目的微信第一批小程序正式低调上线。</li>
</ol>
</blockquote>
<h3 id="ⅱ-小程序的优势">Ⅱ-小程序的优势</h3>
<blockquote>
<ol>
<li>微信有海量⽤⼾,⽽且粘性很⾼,在微信⾥开发产品更容易触达⽤⼾;</li>
<li>推⼴app 或公众号的成本太⾼。</li>
<li>开发适配成本低。</li>
<li>容易⼩规模试错,然后快速迭代。</li>
<li>跨平台。</li>
</ol>
</blockquote>
<h2 id="2小程序准备">2、小程序准备</h2>
<h3 id="ⅰ-环境准备">Ⅰ-环境准备</h3>
<blockquote>
<ol>
<li>安装微信小程序开发工具,建议安装稳定版进行开发</li>
<li>注册小程序账号</li>
<li>使用注册的appid进行使用,如果是测试号会限制很多功能</li>
</ol>
<p>在官网登录成功后可以看到下面的界面,然后复制你的APPID,悄悄的保存起来,<code>不要给别⼈看到</code>😄。</p>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195444222-297307755.png"><br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195523843-2088357023.png"></p>
</blockquote>
<h3 id="ⅱ-新建小程序流程">Ⅱ-新建小程序流程</h3>
<blockquote>
<ol>
<li>打开开发者工具,第一次打开需要扫码登陆</li>
<li>新建小程序项目</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195614790-1006884951.png">
<ol start="3">
<li>填写项目信息</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195659515-1309485572.png">
<ol start="4">
<li>新建成功</li>
</ol>
</blockquote>
<h3 id="ⅲ-微信开发者工具介绍">Ⅲ-微信开发者工具介绍</h3>
<h4 id="1开发工具界面图解">1)开发工具界面图解</h4>
<blockquote>
<p>详细的使⽤,可以查看官⽹:</p>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195749031-1487792190.png"></p>
</blockquote>
<h4 id="2开发工具的一些基本配置">2)开发工具的一些基本配置</h4>
<blockquote>
<ol>
<li>点击<code>工具栏</code>--&gt;<code>详情</code>--&gt;<code>本地设置</code>,除了默认勾选,需要勾选其他的几个如:增强编译、不校验合法域名...</li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195821813-1625710027.png"></p>
<ol start="2">
<li>
<p>常用快捷键<code>keyMap修改</code>设置(本人习惯记录):</p>
<ol>
<li><code>ctrl+P</code>:全局搜索</li>
<li><code>alt+/</code>or <code>shift+j</code>:代码提示</li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195857045-1640617529.png"></p>
</li>
</ol>
</blockquote>
<h3 id="ⅳ-微信小程序名称或者原始id该如何找回">Ⅳ-微信小程序名称或者原始id该如何找回?</h3>
<blockquote>
<p>问题描述:很久没有进行开发了,小程序的名称跟原始id都忘记了,找回需要先填写,如何解决</p>
<p>解决:首先<code>查询自己的原始id</code>,在这个网站能查询到自己的原始id,再通过这个原始id进行找回</p>
</blockquote>
<hr>
<h1 id="二小程序的基本目录结构与文件作用剖析">二、小程序的基本目录结构与文件作用剖析</h1>
<blockquote>
<p>小程序框架的⽬标是通过尽可能简单、⾼效的⽅式让开发者可以在微信中开发具有原⽣APP体验的服务。</p>
<p>⼩程序框架提供了⾃⼰的视图层描述语⾔ <code>WXML 和 WXSS</code> ,以及 JavaScript ,并<code>在视图层与逻辑层间提供了数据传输和事件系统</code>,让开发者能够专注于数据与逻辑。</p>
</blockquote>
<h2 id="1小程序文件结构和传统web对比">1、小程序文件结构和传统web对比</h2>
<blockquote>
<table>
<thead>
<tr>
<th></th>
<th>传统web</th>
<th>微信小程序</th>
</tr>
</thead>
<tbody>
<tr>
<td>项目骨架、结构</td>
<td>HTML</td>
<td>WXML</td>
</tr>
<tr>
<td>页面样式</td>
<td>CSS</td>
<td>WXSS</td>
</tr>
<tr>
<td>项目逻辑</td>
<td>Javascript</td>
<td>Javascript</td>
</tr>
<tr>
<td>配置</td>
<td>无</td>
<td>JSON</td>
</tr>
</tbody>
</table>
<ol>
<li>通过以上对⽐得出传统web是<code>三层结构</code>。⽽微信⼩程序是<code>四层结构</code>,多了⼀层<code>配置.json</code></li>
<li>当这几个文件在同一级目录下且命名相同(后缀不同),可以互相引用却不用导入</li>
</ol>
</blockquote>
<h2 id="2基本的项目目录">2、基本的项目目录</h2>
<h3 id="ⅰ-项目目录解释">Ⅰ-项目目录解释</h3>
<blockquote>
<ol>
<li>
<p>项目目录图解:<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216195943938-586452890.png"></p>
</li>
<li>
<p>以<code>app</code>开头的文件是应用程序级别的文件,更改一处全局生效。而页面<code>pages</code>的配置优先级高于全局配置(<code>就近原则</code>)</p>
</li>
<li>
<p>小程序是允许你修改文件目录名的</p>
</li>
</ol>
</blockquote>
<h2 id="3小程序配置文件">3、小程序配置文件</h2>
<blockquote>
<p>⼀个⼩程序应⽤程序会包括最基本的两种配置⽂件。⼀种是全局的app.json 和 ⻚⾯⾃⼰的page.json</p>
</blockquote>
<h3 id="ⅰ-全局配置appjson">Ⅰ-全局配置app.json</h3>
<blockquote>
<ol>
<li><code>app.json</code> 是当前⼩程序的全局配置,包括了⼩程序的所有⻚⾯路径、界⾯表现、⽹络超时时间、底部tab等。普通快速启动项⽬⾥边的 app.json 配置</li>
<li>代码</li>
</ol>
<pre><code class="language-json">{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
</code></pre>
<ol start="3">
<li>字段的含义</li>
</ol>
<p>1)pages 字段⸺⽤于描述当前⼩程序所有⻚⾯路径,这是为了让微信客⼾端知道当前你的⼩程序⻚⾯定义在哪个⽬录。</p>
<p>​        <code>默认显示此字段中的第一项</code></p>
<p>​        2)window 字段⸺定义⼩程序所有⻚⾯的顶部背景颜⾊,⽂字颜⾊定义等。</p>
<p>​        3)完整的配置信息请参考 app.json配置</p>
<p>​        4) tabBar-底部 <code>tab</code> 栏的表现:<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216200111905-1591969965.png"></p>
<p>更多配置详细请看<code>app配置文档</code></p>
</blockquote>
<h3 id="ⅱ-页面配置pagejson">Ⅱ-页面配置page.json</h3>
<blockquote>
<ol>
<li>这⾥的 <code>page.json</code> 其实⽤来表⽰⻚⾯⽬录下的 page.json 这类和⼩程序⻚⾯相关的配置。 开发者可以独⽴定义每个⻚⾯的⼀些属性,如顶部颜⾊、是否允许下拉刷新等等。 ⻚⾯的配置只能设置 app.json 中部分 window 配置项的内容,⻚⾯中配置项会覆盖 app.json 的 window 中相同的配置项。</li>
<li>常用配置属性列举:</li>
</ol>
<table>
<thead>
<tr>
<th>属性</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>navigationBarBackgroundColor</td>
<td>HexColor</td>
<td>#000000</td>
<td>导航栏背景颜⾊,如 #000000</td>
</tr>
<tr>
<td>navigationBarTextStyle</td>
<td>String</td>
<td>white</td>
<td>导航栏标题颜⾊,仅⽀持 black / white</td>
</tr>
<tr>
<td>navigationBarTitleText</td>
<td>String</td>
<td></td>
<td>导航栏标题⽂字内容</td>
</tr>
<tr>
<td>backgroundColor</td>
<td>HexColor</td>
<td>#ffffff</td>
<td>窗⼝的背景⾊</td>
</tr>
<tr>
<td>backgroundTextStyle</td>
<td>String</td>
<td>dark</td>
<td>下拉<code>loading</code>的样式,仅⽀持 dark / light</td>
</tr>
<tr>
<td>enablePullDownRefresh</td>
<td>Boolean</td>
<td>false</td>
<td>是否全局开启下拉刷新。 详⻅ Page.onPullDownRefresh</td>
</tr>
<tr>
<td>onReachBottomDistance</td>
<td>Number</td>
<td>50</td>
<td>⻚⾯上拉触底事件触发时距⻚⾯底部距离,单位为px。 详⻅ Page.onReachBottom</td>
</tr>
<tr>
<td>disableScroll</td>
<td>Boolean</td>
<td>false</td>
<td>设置为 true 则⻚⾯整体不能上下滚动;只在⻚⾯配置中有效,⽆法在 app.json 中设置该项</td>
</tr>
</tbody>
</table>
</blockquote>
<h3 id="ⅲ-sitemap-配置-了解即可">Ⅲ-sitemap 配置-了解即可</h3>
<blockquote>
<p>⼩程序根⽬录下的 <code>sitemap.json</code> ⽂件⽤于配置⼩程序及其⻚⾯是否允许被微信索引。<code>主要服务于搜索</code></p>
</blockquote>
<h2 id="4小程序框架接口">4、小程序框架接口</h2>
<h3 id="ⅰ-appobject-object">Ⅰ-App(Object object)</h3>
<blockquote>
<ol>
<li>注册小程序。接受一个 <code>Object</code> 参数,其指定小程序的生命周期回调等。</li>
<li><strong>App() 必须在 <code>app.js</code> 中调用,必须调用且只能调用一次。不然会出现无法预期的后果</strong></li>
<li>相应的app()参数在下方的<code>小程序生命周期中有指出</code></li>
</ol>
</blockquote>
<h4 id="appobject-getappobject-object"><strong>AppObject <code>getApp(Object object)</code></strong></h4>
<blockquote>
<ol>
<li>获取到小程序全局唯一的 <code>App</code> 实例。</li>
<li>代码示例</li>
</ol>
<pre><code class="language-jsx">// other.js
var appInstance = getApp()
console.log(appInstance.globalData) // I am global dat
//或者
const {GbaseUrl} =getApp()//GbaseUrl是自己在app.js定义的全局变量
</code></pre>
<ol start="3">
<li>Object object</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">默认值</th>
<th style="text-align: left">必填</th>
<th style="text-align: left">说明</th>
<th style="text-align: left">最低版本</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">allowDefault</td>
<td style="text-align: left">boolean</td>
<td style="text-align: left">false</td>
<td style="text-align: left">否</td>
<td style="text-align: left">在 <code>App</code> 未定义时返回默认实现。当App被调用时,默认实现中定义的属性会被覆盖合并到App中。一般用于独立分包</td>
<td style="text-align: left">2.2.4</td>
</tr>
</tbody>
</table>
<ol start="4">
<li>注意</li>
</ol>
<ul>
<li>不要在定义于 <code>App()</code> 内的函数中,或调用 <code>App</code> 前调用 <code>getApp()</code> 。使用 <code>this</code> 就可以拿到 app 实例。</li>
<li>通过 <code>getApp()</code> 获取实例之后,不要私自调用生命周期函数</li>
</ul>
</blockquote>
<hr>
<h1 id="三小程序的基础知识储备">三、小程序的基础知识储备</h1>
<blockquote>
<p>整个小程序学习过程中遇到的 所需基础知识 或 补充知识 将整合至此</p>
<p>相关知识点本人在<code>一二阶段补缺笔记</code>中有记录,在此便只举例大概,不详细记录</p>
</blockquote>
<h2 id="1flex-布局">1、Flex 布局</h2>
<h3 id="ⅰ-基本知识点概念">Ⅰ-基本知识点概念</h3>
<blockquote>
<ol>
<li>Flex基本概念</li>
</ol>
<ol>
<li>
<p>Flex 是 Flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。</p>
</li>
<li>
<p>任何一个容器都可以指定为 Flex 布局。</p>
</li>
<li>
<p>display: ‘flex’</p>
</li>
</ol>
<p>​<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216200238288-441979457.png"></p>
<p>​        4) 这部分是一阶段基础知识,可看文档学习</p>
<ol start="2">
<li>在小程序中,通常使用<code>&lt;view/&gt;</code>代替<code>&lt;div/&gt;</code>作为容器来做布局--&gt;代码示例在<code>第一章的第三小节第三点</code></li>
</ol>
</blockquote>
<h3 id="ⅱ-解决flex布局中-space-between方法的排版问题">Ⅱ-解决flex布局中 space-between方法的排版问题</h3>
<blockquote>
<p>详见下方<code>杂记-初学阶段遇到的问题与解决-问题Ⅷ</code></p>
</blockquote>
<h2 id="2移动端相关知识点">2、移动端相关知识点</h2>
<blockquote>
<p>自行补充学习,相关知识点本人在<code>一二阶段补缺笔记</code>中有记录,便不再赘述</p>
</blockquote>
<h3 id="ⅰ-物理像素">Ⅰ-物理像素</h3>
<blockquote>
<ol>
<li>
<p>屏幕的分辨率</p>
</li>
<li>
<p>设备能控制显示的最小单元,可以把物理像素看成是对应的像素点</p>
</li>
</ol>
</blockquote>
<h3 id="ⅱ-设备独立像素--css-像素">Ⅱ-设备独立像素 、 css 像素</h3>
<blockquote>
<p>设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用并控制的<code>虚拟像素</code>(比如:CSS 像素,只是在 android 机中 CSS 像素就不叫”CSS 像素”了而是叫”设备独立像素”),然后由相关系统转换为物理像素。</p>
</blockquote>
<h3 id="ⅲ-dpr比-dpi-ppi">Ⅲ-dpr比 、DPI 、PPI</h3>
<blockquote>
<ol>
<li>概念</li>
</ol>
<ol>
<li>
<p>dpr: 设备像素比,物理像素/设备独立像素 = dpr, 一般以 Iphon6 的 dpr 为准 dpr = 2</p>
</li>
<li>
<p>PPI: 一英寸显示屏上的像素点个数</p>
</li>
<li>
<p>DPI:最早指的是打印机在单位面积上打印的墨点数,墨点越多越清晰</p>
</li>
</ol>
<ol start="2">
<li>不同机型对比表</li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216200317385-809251182.png"></p>
<ol start="3">
<li>部分机型图示</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216200343867-60667195.png">
</blockquote>
<h2 id="3移动端适配方案">3、移动端适配方案</h2>
<blockquote>
<p>相关知识点本人在<code>一二阶段补缺笔记</code>中有记录,想详细查阅可以去看,这是个<code>面试考点</code></p>
</blockquote>
<h3 id="ⅰ-viewport-适配">Ⅰ-viewport 适配</h3>
<blockquote>
<ol>
<li>为什么做 <code>viewport</code> 适配 ?</li>
</ol>
<p>a) 手机厂商在生产手机的时候大部分手机默认页面宽度为 980px</p>
<p>b) 手机实际视口宽度都要小于 980px,如: iphone6 为 750px</p>
<p>c) 开发需求需要将 980 的页面完全显示在手机屏幕上且没有滚动条</p>
<ol start="2">
<li>代码实现</li>
</ol>
<pre><code class="language-html">&lt;meta name="viewport" content="width=device-width,initial-scale=1.0"&gt;
</code></pre>
</blockquote>
<h3 id="ⅱ--rem-适配">Ⅱ- rem 适配</h3>
<blockquote>
<ol>
<li>为什么做 <code>rem</code> 适配?</li>
</ol>
<p>a) 机型太多,不同的机型屏幕大小不一样</p>
<p>b) 需求:一套设计稿的内容在不同的机型上呈现的效果一致,根据屏幕大小不同的变化,页面中的内容也相应变化</p>
<ol start="2">
<li>原生代码实现:</li>
</ol>
<pre><code class="language-js">function remRefresh() {
let clientWidth = document.documentElement.clientWidth;
// 将屏幕等分 10 份
let rem = clientWidth / 10;
document.documentElement.style.fontSize = rem + 'px';
document.body.style.fontSize = '12px';
}
window.addEventListener('pageshow', () =&gt; {
remRefresh()
})
// 函数防抖
let timeoutId;
window.addEventListener('resize', () =&gt; {
timeoutId &amp;&amp; clearTimeout(timeoutId);
timeoutId = setTimeout(() =&gt;{
remRefresh()
}, 300)
})
</code></pre>
<ol start="3">
<li>第三方库实现</li>
</ol>
<blockquote>
<p>lib-flexible + px2rem-loader</p>
</blockquote>
</blockquote>
<hr>
<h1 id="四视图层详解">四、视图层详解</h1>
<blockquote>
<p>框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。</p>
<p>将逻辑层的数据反映成视图,同时将视图层的事件发送给逻辑层。</p>
<p>WXML(WeiXin Markup language) 用于描述页面的结构。</p>
<p>WXS(WeiXin Script) 是小程序的一套脚本语言,结合 <code>WXML</code>,可以构建出页面的结构。</p>
<p>WXSS(WeiXin Style Sheet) 用于描述页面的样式。</p>
<p>组件(Component)是视图的基本组成单元。</p>
<p>该部分将<code>截取官方文档</code>并加以注解</p>
</blockquote>
<h2 id="1wxss样式文件详解">1、WXSS样式文件详解</h2>
<blockquote>
<ol>
<li>WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。</li>
<li>WXSS 用来决定 WXML 的组件应该怎么显示。</li>
</ol>
<p>为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。</p>
<ol start="3">
<li>与 CSS 相比,WXSS 扩展的特性有:
<ol>
<li>响应式⻓度单位:即尺寸单位 --&gt;<code>rpx</code></li>
<li>样式导入</li>
</ol>
</li>
<li>注意:</li>
</ol>
<p>当页面文件在同一级目录下且命名相同(后缀不同),<code>可以互相引用却不用导入</code></p>
</blockquote>
<h3 id="ⅰ-尺寸单位">Ⅰ-尺寸单位</h3>
<blockquote>
<ol>
<li><code>rpx(responsive pixel)</code>: 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 <code>iPhone6</code> 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">设备</th>
<th style="text-align: left">rpx换算px (屏幕宽度/750)</th>
<th style="text-align: left">px换算rpx (750/屏幕宽度)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">iPhone5</td>
<td style="text-align: left">1rpx = 0.42px</td>
<td style="text-align: left">1px = 2.34rpx</td>
</tr>
<tr>
<td style="text-align: left">iPhone6</td>
<td style="text-align: left">1rpx = 0.5px</td>
<td style="text-align: left">1px = 2rpx</td>
</tr>
<tr>
<td style="text-align: left">iPhone6 Plus</td>
<td style="text-align: left">1rpx = 0.552px</td>
<td style="text-align: left">1px = 1.81rpx</td>
</tr>
</tbody>
</table>
<ol start="2">
<li>建议与注意点:
<ol>
<li>开发微信小程序时<code>推荐设计师可以用iPhone6作为视觉稿的标准</code>--&gt;即只有在<code>iPhone6</code>标准中才可以<code>一比二换算</code>,更方便</li>
<li>在较小的屏幕上不可避免的会有一些毛刺,请在开发时尽量避免这种情况</li>
</ol>
</li>
</ol>
</blockquote>
<h3 id="ⅱ-样式导">Ⅱ-样式导⼊</h3>
<blockquote>
<ol>
<li>使用<code>@import</code>语句可以导入外联样式表,也可以和less中的导⼊混⽤,<code>@import</code>后跟需要导入的外联样式表的<code>相对路径</code>(只⽀持相对路径),用<code>;</code>表示语句结束。</li>
</ol>
<pre><code class="language-css">/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
padding:15px;
}
</code></pre>
</blockquote>
<h3 id="ⅲ-内联样式">Ⅲ-内联样式</h3>
<blockquote>
<p>框架组件上支持使用 style、class 属性来控制组件的样式。</p>
<ol>
<li><code>style</code>:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度</li>
</ol>
<pre><code class="language-html">&lt;view style="color:{{color}};" /&gt;
</code></pre>
<ol start="2">
<li><code>class</code>:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上<code>.</code>,样式类名之间用空格分隔</li>
</ol>
<pre><code class="language-html">&lt;view class="normal_view" /&gt;
</code></pre>
</blockquote>
<h2 id="2wxml语法详解">2、WXML语法详解</h2>
<blockquote>
<p>WXML(WeiXin Markup Language)是框架设计的⼀套标签语⾔,结合基础组件、事件系统,可以构建出⻚⾯的结构。</p>
<p>该部分将<code>截取官方文档</code>加以自己见解说明,同学们也可以直接去看文档</p>
</blockquote>
<h3 id="ⅰ-数据绑定与写法规则">Ⅰ-数据绑定与写法规则</h3>
<blockquote>
<ol>
<li>WXML 中的动态数据均来自对应 Page 的 data。</li>
<li>Mustache 语法{{}}视作运算标记,里面的内容表示表达式</li>
</ol>
</blockquote>
<h4 id="1-单向简单数据绑定">1) 单向简单数据绑定</h4>
<blockquote>
<ol>
<li>此处是单向绑定(数据驱动视图),双向绑定出现的场景如(input等)将在下方<code>四-3、双向绑定</code>处记录</li>
<li><code>简单绑定</code>:数据绑定使用 Mustache 语法(双大括号)将变量包起来,可以作用于:</li>
</ol>
<pre><code class="language-jsx">//pages.wxml
&lt;view&gt; {{ message }} &lt;/view&gt;

// pages.js
Page({
data: {
message: 'Hello MINA!'
}
})
</code></pre>
<ol start="3">
<li>绑定<code>boolean</code>类型(需要在双引号之内)</li>
</ol>
<p><code>true</code>:boolean 类型的 true,代表真值。<code>false</code>: boolean 类型的 false,代表假值。</p>
<pre><code class="language-jsx">&lt;checkbox checked="{{false}}"&gt; &lt;/checkbox&gt;
</code></pre>
<p><em><strong>特别注意:不要直接写 <code>checked="false"</code>,其计算结果是一个字符串,转成 boolean 类型后代表真值</strong></em></p>
</blockquote>
<h4 id="2-运算">2) 运算</h4>
<blockquote>
<p>可以在 <code>{{}}</code> 内进行简单的运算,支持的有如下几种方式:</p>
<ol>
<li>三元运算</li>
</ol>
<pre><code class="language-jsx">&lt;view hidden="{{flag ? true : false}}"&gt; Hidden &lt;/view&gt;
</code></pre>
<ol start="2">
<li>算数运算</li>
</ol>
<pre><code class="language-jsx">&lt;view&gt; {{a + b}} + {{c}} + d &lt;/view&gt;
//view中的内容为 `3 + 3 + d`。
//pages.js
Page({
data: { a: 1, b: 2, c: 3
}
})
</code></pre>
<ol start="3">
<li>逻辑判断</li>
</ol>
<pre><code class="language-jsx">&lt;view wx:if="{{length &gt; 5}}"&gt; &lt;/view&gt;
</code></pre>
<ol start="4">
<li>字符串运算</li>
</ol>
<pre><code class="language-jsx">&lt;view&gt;{{"hello" + name}}&lt;/view&gt;
Page({
data:{name: 'MINA}
})
</code></pre>
<ol start="5">
<li>数据路径运算</li>
</ol>
<pre><code class="language-jsx">&lt;view&gt;{{object.key}} {{array}}&lt;/view&gt;
//view中的内容为 helloMINA
Page({
data: {
object: {
    key: 'Hello '
},
array: ['MINA']
}
})
</code></pre>
</blockquote>
<h4 id="3-组合">3) 组合</h4>
<blockquote>
<p>也可以在 Mustache 内直接进行组合,构成新的对象或者数组。</p>
<ol>
<li>数组 --&gt; 最终组合成数组<code></code>。</li>
</ol>
<pre><code class="language-jsx">&lt;view wx:for="{{}}"&gt; {{item}} &lt;/view&gt;
Page({
data: { zero: 0 }
})
</code></pre>
<ol start="2">
<li>对象   --&gt;
<ol>
<li>最终组合成的对象是 <code>{for: 1, bar: 2}</code></li>
</ol>
</li>
</ol>
<pre><code class="language-JSx">&lt;template is="objectCombine" data="{{for: a, bar: b}}"&gt;&lt;/template&gt;
Page({
    data: {a: 1, b: 2}
})
</code></pre>
<ol start="2">
<li>也可以用扩展运算符 <code>...</code> 来将一个对象展开--&gt;最终组合成的对象是 <code>{a: 1, b: 2, c: 3, d: 4, e: 5}</code>。</li>
</ol>
<pre><code class="language-JSx">&lt;template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"&gt;&lt;/template&gt;
Page({
    data: {
      obj1: { a: 1, b: 2 },
      obj2: { c: 3, d: 4}
    }
})

</code></pre>
<ol start="3">
<li>如果对象的 key 和 value 相同,也可以间接地表达。--&gt;最终组合成的对象是 <code>{foo: 'my-foo', bar:'my-bar'}</code></li>
</ol>
<pre><code class="language-JSx">&lt;template is="objectCombine" data="{{foo, bar}}"&gt;&lt;/template&gt;
Page({
    data: {
      foo: 'my-foo',
      bar: 'my-bar'
    }
})

</code></pre>
<ol start="4">
<li><code>注意</code>:上述方式可以随意组合,但是如有存在变量名相同的情况,后边的会覆盖前面 --&gt; 最终组合成的对象是 <code>{a: 5, b: 3, c: 6}</code>。</li>
</ol>
<pre><code class="language-JSx">&lt;template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"&gt;&lt;/template&gt;
Page({
    data: {
      obj1: { a: 1,b: 2},
      obj2: { b: 3, c: 4},
      a: 5
    }
})

</code></pre>
<ol start="5">
<li><code>注意</code>: 花括号和引号之间如果有空格,将最终被解析成为字符串</li>
</ol>
<pre><code class="language-JSx">    &lt;view wx:for="{{}} "&gt;
      {{item}}
    &lt;/view&gt;
    等同于
                        
    &lt;view wx:for="{{ + ' '}}"&gt;
      {{item}}
    &lt;/view&gt;

</code></pre>
</blockquote>
<h4 id="4-自定义属性data-的命名与使用">4) 自定义属性<code>data-*</code>的命名与使用</h4>
<blockquote>
<ol>
<li>同一容器中可以存在多个<code>data-*</code></li>
<li>凡是以<code>data-</code>开头的数据,都会在<code>event的currentTarget</code>中体现,且回缺省<code>data-</code>(data-id--&gt;id)</li>
<li><code>data-*</code>后面接的单词将自动转换 第一个单词首字母小写,第二个及之后的单词首字母大写 (data-post-my-id --&gt; postMyId)</li>
</ol>
</blockquote>
<h3 id="ⅱ-列表渲染">Ⅱ-列表渲染</h3>
<h4 id="1-wxfor">1) wx:for</h4>
<blockquote>
<ol>
<li>在组件上使用 <code>wx:for</code> 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。</li>
<li>默认数组的当前项的下标变量名默认为 <code>index</code>,数组当前项的变量名默认为 <code>item</code></li>
<li>使用 <code>wx:for-item</code> 可以指定数组当前元素的变量名,使用 <code>wx:for-index</code> 可以指定数组当前下标的变量名:</li>
</ol>
<pre><code class="language-jsx">&lt;view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"&gt;
{{idx}}: {{itemName.message}}
&lt;/view&gt;

</code></pre>
<ol start="4">
<li><code>wx:for</code> 也可以嵌套,下边是一个九九乘法表</li>
</ol>
<pre><code class="language-jsx">&lt;view wx:for="{{}}" wx:for-item="i"&gt;
&lt;view wx:for="{{}}" wx:for-item="j"&gt;
&lt;view wx:if="{{i &lt;= j}}"&gt;
    {{i}} * {{j}} = {{i * j}}
&lt;/view&gt;
&lt;/view&gt;
&lt;/view&gt;

</code></pre>
</blockquote>
<h4 id="2-block-wxfor">2) block wx:for</h4>
<blockquote>
<p>类似 <code>block wx:if</code>,也可以将 <code>wx:for</code> 用在<code>&lt;block/&gt;</code>标签上,以渲染一个包含多节点的结构块。例如:</p>
<pre><code class="language-jsx">&lt;block wx:for="{{}}"&gt;
&lt;view&gt; {{index}}: &lt;/view&gt;
&lt;view&gt; {{item}} &lt;/view&gt;
&lt;/block&gt;

</code></pre>
<p><strong>注意:</strong> <code>&lt;block/&gt;</code> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性</p>
</blockquote>
<h4 id="3-wxkey">3) wx:key</h4>
<blockquote>
<p>如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 <code>wx:key</code> 来指定列表中项目的唯一的标识符。</p>
</blockquote>
<h5 id="-wxkey-的值以两种形式提供">① <code>wx:key</code> 的值以两种形式提供</h5>
<blockquote>
<ol>
<li>字符串,代表在for循环的array中<code>item的某个property</code>,该property的值需要是列表中唯一的字符串或数字,且不能动态改变。</li>
<li>保留关键字 <code>*this</code> 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个<code>唯一的字符串或者数字</code>。</li>
</ol>
<pre><code class="language-JSX">&lt;block wx:for="{{posts}}"   wx:key="id"&gt;&lt;/blocK&gt;
//id是posts数组中的对象里的一个属性

</code></pre>
</blockquote>
<h5 id="使用-wxkey-的意义">②使用 <code>wx:key</code> 的意义</h5>
<blockquote>
<p>当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件<code>,框架会确保他们被重新排序,而不是重新创建</code>,以确保使组件保持自身的状态,并且提高列表渲染时的效率。</p>
<p>如不提供 <code>wx:key</code>,会报一个 <code>warning</code>, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。</p>
</blockquote>
<h4 id="4-列表渲染注意点">4) 列表渲染注意点</h4>
<h5 id="-当-wxfor-的值为字符串时会将字符串解析成字符串数组">① 当 <code>wx:for</code> 的值为字符串时,会将字符串解析成字符串数组</h5>
<blockquote>
<pre><code class="language-jsx">&lt;view wx:for="array"&gt;
{{item}}
&lt;/view&gt;
等同于

&lt;view wx:for="{{['a','r','r','a','y']}}"&gt;
{{item}}
&lt;/view&gt;

</code></pre>
</blockquote>
<h5 id="-花括号和引号之间如果有空格将最终被解析成为字符串">② 花括号和引号之间如果有空格,将最终被解析成为字符串</h5>
<blockquote>
<pre><code class="language-jsx">&lt;view wx:for="{{}} "&gt;
{{item}}
&lt;/view&gt;
等同于

&lt;view wx:for="{{ + ' '}}" &gt;
{{item}}
&lt;/view&gt;

</code></pre>
</blockquote>
<h3 id="ⅲ-条件渲染">Ⅲ-条件渲染</h3>
<h4 id="1-wxif">1) wx:if</h4>
<blockquote>
<ol>
<li>在框架中,使用 <code>wx:if=""</code> 来判断是否需要渲染该代码块:</li>
</ol>
<pre><code class="language-jsx">&lt;view wx:if="{{condition}}"&gt; True &lt;/view&gt;

</code></pre>
<ol start="2">
<li>也可以用 <code>wx:elif</code> 和 <code>wx:else</code> 来添加一个 else 块:</li>
</ol>
<pre><code class="language-jsx">&lt;view wx:if="{{length &gt; 5}}"&gt; 1 &lt;/view&gt;
&lt;view wx:elif="{{length &gt; 2}}"&gt; 2 &lt;/view&gt;
&lt;view wx:else&gt; 3 &lt;/view&gt;

</code></pre>
</blockquote>
<h4 id="2-block-wxif">2) block wx:if</h4>
<blockquote>
<p>因为 <code>wx:if</code> 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <code>&lt;block/&gt;</code> 标签将多个组件包装起来,并在上边使用 <code>wx:if</code> 控制属性</p>
<pre><code class="language-jsx">&lt;block wx:if="{{true}}"&gt;
&lt;view&gt; view1 &lt;/view&gt;
&lt;view&gt; view2 &lt;/view&gt;
&lt;/block&gt;

</code></pre>
<p><strong>注意:</strong> <code>&lt;block/&gt;</code> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性</p>
</blockquote>
<h4 id="3-wxif-vs-hidden">3) <code>wx:if</code> vs <code>hidden</code></h4>
<blockquote>
<ol>
<li>因为 <code>wx:if</code> 之中的模板也可能包含数据绑定,所以当 <code>wx:if</code> 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。</li>
<li>同时 <code>wx:if</code> 也是<strong>惰性的</strong>,如果在初始渲染条件为 <code>false</code>,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。</li>
</ol>
<p>相比之下,<code>hidden</code> 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。</p>
<ol start="3">
<li>一般来说,<code>wx:if</code> 有更高的切换消耗而 <code>hidden</code> 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 <code>hidden</code> 更好,如果在运行时条件不大可能改变则 <code>wx:if</code> 较好。</li>
</ol>
</blockquote>
<h3 id="ⅳ-模板">Ⅳ-模板</h3>
<blockquote>
<ol>
<li>WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用</li>
<li>模板拥有自己的<code>作用域</code>,只能使用 <code>data</code> 传入的数据以及模板定义文件中定义的 <code>&lt;wxs /&gt;</code> 模块。</li>
</ol>
</blockquote>
<h4 id="1-定义模板">1) 定义模板</h4>
<blockquote>
<p>使用 name 属性,作为模板的名字。然后在<code>&lt;template/&gt;</code>内定义代码片段,如</p>
<pre><code class="language-jsx">&lt;!--
index: int
msg: string
time: string
--&gt;
&lt;template name="msgItem"&gt;
&lt;view&gt;
&lt;text&gt; {{index}}: {{msg}} &lt;/text&gt;
&lt;text&gt; Time: {{time}} &lt;/text&gt;
&lt;/view&gt;
&lt;/template&gt;

</code></pre>
</blockquote>
<h4 id="2-使用模板">2) 使用模板</h4>
<blockquote>
<ol>
<li>使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:</li>
</ol>
<pre><code class="language-jsx">&lt;template is="msgItem" data="{{...item}}"/&gt;
Page({
data: {
item: { index: 0, msg: 'this is a template', time: '2016-09-15'}
}
})

</code></pre>
<ol start="2">
<li>is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:</li>
</ol>
<pre><code class="language-jsx">&lt;template name="odd"&gt;
&lt;view&gt; odd &lt;/view&gt;
&lt;/template&gt;
&lt;template name="even"&gt;
&lt;view&gt; even &lt;/view&gt;
&lt;/template&gt;

&lt;block wx:for="{{}}"&gt;
&lt;template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/&gt;
&lt;/block&gt;

</code></pre>
</blockquote>
<h3 id="ⅴ-引用">Ⅴ-引用</h3>
<blockquote>
<p>WXML 提供两种文件引用方式<code>import</code>和<code>include</code></p>
</blockquote>
<h4 id="1-import">1) import</h4>
<h5 id="-使用示例">① 使用示例</h5>
<blockquote>
<ol>
<li>在 item.wxml 中定义了一个叫<code>item</code>的<code>template</code>:</li>
</ol>
<pre><code class="language-jsx">&lt;!-- item.wxml --&gt;
&lt;template name="item"&gt;
&lt;text&gt;{{text}}&lt;/text&gt;
&lt;/template&gt;

</code></pre>
<ol start="2">
<li>在 index.wxml 中引用了 item.wxml,就可以使用<code>item</code>模板:</li>
</ol>
<pre><code class="language-jsx">&lt;import src="item.wxml"/&gt;
&lt;template is="item" data="{{text: 'forbar'}}"/&gt;

</code></pre>
</blockquote>
<h5 id="-import-的作用域">② import 的作用域</h5>
<blockquote>
<p>import有作用域的概念,即只会 import 目标文件中定义的 template,而不会import目标文件import的template。</p>
<p><strong>如:C import B,B import A,在C中可以使用B定义的<code>template</code>,在B中可以使用A定义的<code>template</code>,但是C不能使用A定义的<code>template</code></strong>。</p>
<pre><code class="language-jsx">&lt;!-- A.wxml --&gt;
&lt;template name="A"&gt;
&lt;text&gt; A template &lt;/text&gt;
&lt;/template&gt;
&lt;!-- B.wxml --&gt;
&lt;import src="a.wxml"/&gt;
&lt;template name="B"&gt;
&lt;text&gt; B template &lt;/text&gt;
&lt;/template&gt;
&lt;!-- C.wxml --&gt;
&lt;import src="b.wxml"/&gt;
&lt;template is="A"/&gt;&lt;!-- Error! Can not use tempalte when not import A. --&gt;
&lt;template is="B"/&gt;

</code></pre>
</blockquote>
<h4 id="2-include">2) include</h4>
<blockquote>
<p><code>include</code> 可以将目标文件<strong>除了</strong> <code>&lt;template/&gt;</code> <code>&lt;wxs/&gt;</code> 外的整个代码引入,相当于是拷贝到 <code>include</code> 位置,如:</p>
<pre><code class="language-jsx">&lt;!-- index.wxml --&gt;
&lt;include src="header.wxml"/&gt;
&lt;view&gt; body &lt;/view&gt;
&lt;include src="footer.wxml"/&gt;
&lt;!-- header.wxml --&gt;
&lt;view&gt; header &lt;/view&gt;
&lt;!-- footer.wxml --&gt;
&lt;view&gt; footer &lt;/view&gt;

</code></pre>
</blockquote>
<h2 id="3双向绑定">3、双向绑定</h2>
<h3 id="ⅰ-双向绑定语法">Ⅰ-双向绑定语法</h3>
<blockquote></blockquote>
<h3 id="ⅱ--setdata--数据更新">Ⅱ- <code>setData</code>--&gt;数据更新</h3>
<blockquote>
<ol>
<li><code>setData</code> 是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口。</li>
<li>小程序的视图层目前使用 WebView 作为渲染载体,而逻辑层是由独立的 JavascriptCore 作为运行环境。在架构上,WebView 和 JavascriptCore 都是独立的模块,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 <code>evaluateJavascript</code> 所实现。即用户传输的数据,①<code>需要将其转换为字符串形式传递</code>,② <code>同时把转换后的数据内容拼接成一份 JS 脚本</code>,③<code>再通过执行 JS 脚本的形式传递到两边独立环境</code>。</li>
<li>而 <code>evaluateJavascript</code> 的执行会受很多方面的影响,数据到达视图层并不是实时的</li>
</ol>
</blockquote>
<h4 id="1-简单使用">1) 简单使用</h4>
<blockquote>
<p><code>setData</code>可以直接将数据加入data中;如果在data中已经有该值,则修改它有着创建+更新功能但正常是用来更新</p>
<pre><code class="language-jsx">Page({
data: {posts: [],test: "测试数据",flag: true},
//更新
        this.setData({posts: content})
})

</code></pre>
</blockquote>
<h4 id="2-常见的-setdata-操作错误">2) 常见的 setData 操作错误</h4>
<h5 id="-频繁的去-setdata">① <strong>频繁的去 setData</strong></h5>
<blockquote>
<p>在我们分析过的一些案例里,部分小程序会非常频繁(毫秒级)的去<code>setData</code>,其导致了两个后果:</p>
<ul>
<li>Android 下用户在滑动时会感觉到卡顿,操作反馈延迟严重,因为 JS 线程一直在编译执行渲染,未能及时将用户操作事件传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层;</li>
<li>渲染有出现延时,由于 WebView 的 JS 线程一直处于忙碌状态,逻辑层到页面层的通信耗时上升,视图层收到的数据消息时距离发出时间已经过去了几百毫秒,渲染的结果并不实时;</li>
</ul>
</blockquote>
<h5 id="-每次-setdata-都传递大量新数据">② <strong>每次 setData 都传递大量新数据</strong></h5>
<blockquote>
<p>由<code>setData</code>的底层实现可知,我们的数据传输实际是一次 <code>evaluateJavascript</code> 脚本过程,当数据量过大时会增加脚本的编译执行时间,占用 WebView JS 线程,</p>
</blockquote>
<h5 id="-后台态页面进行-setdata">③ <strong>后台态页面进行 setData</strong></h5>
<blockquote>
<p>当页面进入后台态(用户不可见),不应该继续去进行<code>setData</code>,后台态页面的渲染用户是无法感受的,另外后台态页面去<code>setData</code>也会抢占前台页面的执行</p>
</blockquote>
<h2 id="4事件系统">4、事件系统</h2>
<h3 id="ⅰ-什么是事件">Ⅰ-什么是事件?</h3>
<blockquote>
<ul>
<li><code>事件是视图层到逻辑层的通讯方式</code>。</li>
<li>事件可以将用户的行为反馈到逻辑层进行处理。</li>
<li>事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。</li>
<li>事件对象可以携带额外信息,如 id, dataset, touches。</li>
</ul>
</blockquote>
<h3 id="ⅱ-事件分类">Ⅱ-事件分类</h3>
<blockquote>
<p>事件分为冒泡事件和非冒泡事件:</p>
<ol>
<li><code>冒泡事件</code>:当一个组件上的事件被触发后,该事件会向父节点传递。</li>
<li><code>非冒泡事件</code>:当一个组件上的事件被触发后,该事件不会向父节点传递。</li>
<li>WXML的冒泡事件列表:</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">类型</th>
<th style="text-align: left">触发条件</th>
<th style="text-align: left">最低版本</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">touchstart</td>
<td style="text-align: left">手指触摸动作开始</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">touchmove</td>
<td style="text-align: left">手指触摸后移动</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">touchcancel</td>
<td style="text-align: left">手指触摸动作被打断,如来电提醒,弹窗</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">touchend</td>
<td style="text-align: left">手指触摸动作结束</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">tap</td>
<td style="text-align: left">手指触摸后马上离开</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">longpress</td>
<td style="text-align: left">手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发</td>
<td style="text-align: left">1.5.0</td>
</tr>
<tr>
<td style="text-align: left">longtap</td>
<td style="text-align: left">手指触摸后,超过350ms再离开(推荐使用longpress事件代替)</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">transitionend</td>
<td style="text-align: left">会在 WXSS transition 或 wx.createAnimation 动画结束后触发</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">animationstart</td>
<td style="text-align: left">会在一个 WXSS animation 动画开始时触发</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">animationiteration</td>
<td style="text-align: left">会在一个 WXSS animation 一次迭代结束时触发</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">animationend</td>
<td style="text-align: left">会在一个 WXSS animation 动画完成时触发</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">touchforcechange</td>
<td style="text-align: left">在支持 3D Touch 的 iPhone 设备,重按时会触发</td>
<td style="text-align: left">1.9.90</td>
</tr>
</tbody>
</table>
<ol start="4">
<li><code>注</code>:除上表之外的其他组件自定义事件如无特殊声明<code>都是非冒泡事件</code>,如 form 的<code>submit</code>事件,input 的<code>input</code>事件,scroll-view 的<code>scroll</code>事件,(详见各个组件)</li>
</ol>
</blockquote>
<h3 id="ⅲ-事件的绑定方式">Ⅲ-事件的绑定方式</h3>
<h4 id="1-普通事件绑定-bind-绑定">1) 普通事件绑定-<code>bind</code> 绑定</h4>
<blockquote>
<ol>
<li>代码示例</li>
</ol>
<pre><code class="language-jsx">&lt;view bindtap="tapName" class='start_container'&gt;
//也可以加冒号分隔
        //&lt;view bind:tap="tapName" class='start_container'&gt;
&lt;text class='start'&gt;开启小程序之旅&lt;/text&gt;
&lt;/view&gt;
Page({
tapName: function(event) { console.log(event)}
})

</code></pre>
<ol start="2">
<li>如果用户点击这个 view ,则页面的 <code>tapName</code> 会被调用。</li>
<li>此时,页面的 <code>this.data.tapName</code> 必须是一个字符串,指定事件处理函数名;如果它是个空字符串,则这个绑定会失效(可以利用这个特性来暂时禁用一些事件)</li>
<li>自基础库版本 1.5.0 起,在大多数组件和自定义组件中, <code>bind</code> 后可以紧跟一个冒号,其含义不变,如 <code>bind:tap</code> 。基础库版本 2.8.1 起,在所有组件中开始提供这个支持。</li>
</ol>
</blockquote>
<h4 id="2-绑定并阻止事件冒泡-catch-绑定">2) 绑定并阻止事件冒泡-<code>catch</code> 绑定:</h4>
<blockquote>
<ol>
<li>除 <code>bind</code> 外,也可以用 <code>catch</code> 来绑定事件。与 <code>bind</code> 不同, <code>catch</code> 会阻止事件向上冒泡。</li>
<li>代码示例:</li>
</ol>
<pre><code class="language-jsx">&lt;view id="outer" bindtap="handleTap1"&gt;
outer view
&lt;view id="middle" catchtap="handleTap2"&gt;
middle view
&lt;view id="inner" bindtap="handleTap3"&gt;
    inner view
&lt;/view&gt;
&lt;/view&gt;
&lt;/view&gt;

</code></pre>
<ol start="3">
<li>例如在上边这个例子中,点击 inner view 会先后调用<code>handleTap3</code>和<code>handleTap2</code>(因为tap事件会冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父节点传递),点击 middle view 会触发<code>handleTap2</code>,点击 outer view 会触发<code>handleTap1</code>。</li>
</ol>
</blockquote>
<h4 id="3-互斥事件绑定">3) 互斥事件绑定</h4>
<blockquote>
<ol>
<li>自基础库版本 2.8.2 起,除 <code>bind</code> 和 <code>catch</code> 外,还可以使用 <code>mut-bind</code> 来绑定事件。一个 <code>mut-bind</code> 触发后,如果事件冒泡到其他节点上,其他节点上的 <code>mut-bind</code> 绑定函数不会被触发,但 <code>bind</code> 绑定函数和 <code>catch</code> 绑定函数依旧会被触发。</li>
<li>换而言之,所有 <code>mut-bind</code> 是“互斥”的,只会有其中一个绑定函数被触发。同时,它完全不影响 <code>bind</code> 和 <code>catch</code> 的绑定效果</li>
<li>例如在下边这个例子中,点击 inner view 会先后调用 <code>handleTap3</code> 和 <code>handleTap2</code> ,点击 middle view 会调用 <code>handleTap2</code> 和 <code>handleTap1</code></li>
</ol>
<pre><code class="language-jsx">&lt;view id="outer" mut-bind:tap="handleTap1"&gt;
outer view
&lt;view id="middle" bindtap="handleTap2"&gt;
middle view
&lt;view id="inner" mut-bind:tap="handleTap3"&gt;
    inner view
&lt;/view&gt;
&lt;/view&gt;
&lt;/view&gt;

</code></pre>
</blockquote>
<h3 id="ⅳ-事件的捕获阶段">Ⅳ-事件的捕获阶段</h3>
<blockquote>
<ol>
<li>自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段<code>恰好相反</code>。需要在捕获阶段监听事件时,可以采用<code>capture-bind</code>、<code>capture-catch</code>关键字,后者将中断捕获阶段和取消冒泡阶段。</li>
<li>在下面的代码中,点击 inner view 会先后调用<code>handleTap2</code>、<code>handleTap4</code>、<code>handleTap3</code>、<code>handleTap1</code></li>
</ol>
<pre><code class="language-jsx">&lt;view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2"&gt;
outer view
&lt;view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4"&gt;
inner view
&lt;/view&gt;
&lt;/view&gt;

</code></pre>
<p>如果将上面代码中的第一个capture-bind改为capture-catch,将<code>只触发handleTap2</code>。</p>
<pre><code class="language-jsx">&lt;view id="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2"&gt;
outer view
&lt;view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4"&gt;
inner view
&lt;/view&gt;
&lt;/view&gt;

</code></pre>
</blockquote>
<h3 id="ⅴ-事件对象">Ⅴ-事件对象</h3>
<blockquote>
<p>如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象。</p>
</blockquote>
<h4 id="1-baseevent-基础事件对象属性列表">1) <strong>BaseEvent 基础事件对象属性列表</strong></h4>
<blockquote>
<ol>
<li>表格:</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">说明</th>
<th style="text-align: left">基础库版本</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">type</td>
<td style="text-align: left">String</td>
<td style="text-align: left">代表事件的类型</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">timeStamp</td>
<td style="text-align: left">Integer</td>
<td style="text-align: left">事件生成时的时间戳--页面打开到触发事件所经过的毫秒数</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">target</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">触发事件的组件的一些属性值集合--触发事件的源组件</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">currentTarget</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">当前组件的一些属性值集合--事件绑定的当前组件</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">mark</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">事件标记数据</td>
<td style="text-align: left">2.7.1</td>
</tr>
</tbody>
</table>
<ol start="2">
<li>补充说明</li>
<li>target</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">id</td>
<td style="text-align: left">String</td>
<td style="text-align: left">事件源组件的id</td>
</tr>
<tr>
<td style="text-align: left">dataset</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">事件源组件上由<code>data-</code>开头的自定义属性组成的集合</td>
</tr>
</tbody>
</table>
<ol start="2">
<li>currentTarget</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">id</td>
<td style="text-align: left">String</td>
<td style="text-align: left">当前组件的id</td>
</tr>
<tr>
<td style="text-align: left">dataset</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">当前组件上由<code>data-</code>开头的自定义属性组成的集合</td>
</tr>
</tbody>
</table>
<p><code>说明</code>: target 和 currentTarget 可以参考上例中,点击 inner view 时,<code>handleTap3</code> 收到的事件对象 target 和 currentTarget 都是 inner,而 <code>handleTap2</code> 收到的事件对象 target 就是 inner,currentTarget 就是 middle</p>
</blockquote>
<h4 id="2-touchevent-触摸事件对象属性列表继承-baseevent">2) <strong>TouchEvent 触摸事件对象属性列表(继承 BaseEvent):</strong></h4>
<blockquote>
<ol>
<li>表格:</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">touches</td>
<td style="text-align: left">Array</td>
<td style="text-align: left">触摸事件,当前停留在屏幕中的触摸点信息的数组</td>
</tr>
<tr>
<td style="text-align: left">changedTouches</td>
<td style="text-align: left">Array</td>
<td style="text-align: left">触摸事件,当前变化的触摸点信息的数组</td>
</tr>
</tbody>
</table>
<ol start="2">
<li>补充说明</li>
<li>touches</li>
</ol>
<p>touches 是一个数组,每个元素为一个 Touch 对象(canvas 触摸事件中携带的 touches 是 CanvasTouch 数组)。 表示当前停留在屏幕上的触摸点。</p>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">identifier</td>
<td style="text-align: left">Number</td>
<td style="text-align: left">触摸点的标识符</td>
</tr>
<tr>
<td style="text-align: left">pageX, pageY</td>
<td style="text-align: left">Number</td>
<td style="text-align: left">距离文档左上角的距离,文档的左上角为原点 ,横向为X轴,纵向为Y轴</td>
</tr>
<tr>
<td style="text-align: left">clientX, clientY</td>
<td style="text-align: left">Number</td>
<td style="text-align: left">距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴</td>
</tr>
</tbody>
</table>
<ol start="2">
<li>changedTouches</li>
</ol>
<p>changedTouches 数据格式同 touches。 表示有变化的触摸点,如从无变有(touchstart),位置变化(touchmove),从有变无(touchend、touchcancel)</p>
</blockquote>
<h4 id="3-customevent-自定义事件对象属性列表继承-baseevent">3) <strong>CustomEvent 自定义事件对象属性列表(继承 BaseEvent):</strong></h4>
<blockquote>
<ol>
<li>表格</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">detail</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">额外的信息<br>自定义事件所携带的数据,如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息,详见组件定义中各个事件的定义。</td>
</tr>
</tbody>
</table>
</blockquote>
<hr>
<h1 id="五逻辑层详解">五、逻辑层详解</h1>
<blockquote>
<ol>
<li>原理:小程序开发框架的逻辑层使用 <code>JavaScript</code> 引擎为小程序提供开发者 <code>JavaScript</code> 代码的运行环境以及微信小程序的特有功能。</li>
</ol>
<p>​        逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。</p>
<p>​        开发者写的所有代码最终将会打包成一份 <code>JavaScript</code> 文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似ServiceWorker,所以逻辑层也称之为 App Service。</p>
<ol start="2">
<li>在 <code>JavaScript</code> 的基础上,我们增加了一些功能,以方便小程序的开发:</li>
</ol>
<ul>
<li>增加 <code>App</code> 和 <code>Page</code> 方法,进行程序注册和页面注册。</li>
<li>增加 <code>getApp</code> 和 <code>getCurrentPages</code> 方法,分别用来获取 <code>App</code> 实例和当前页面栈。</li>
<li>提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。</li>
<li>提供模块化能力,每个页面有独立的作用域。</li>
</ul>
<p><strong>注意:小程序框架的逻辑层并非运行在浏览器中,因此 <code>JavaScript</code> 在 web 中一些能力都无法使用,如 <code>window</code>,<code>document</code> 等。</strong></p>
<p>该部分将<code>截取官方文档</code>并加以注解</p>
</blockquote>
<h2 id="1页面路由">1、页面路由</h2>
<blockquote>
<p>在小程序中所有页面的路由全部由框架进行管理</p>
</blockquote>
<h3 id="ⅰ-页面栈与路由方式">Ⅰ-页面栈与路由方式</h3>
<blockquote>
<ol>
<li>框架以<code>栈</code>的形式维护了当前的所有页面。</li>
<li>对于路由的<code>触发方式</code>以及页面<code>生命周期函数</code>如下:</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">路由方式</th>
<th>页面栈表现</th>
<th style="text-align: left">触发时机</th>
<th style="text-align: left">路由前页面</th>
<th style="text-align: left">路由后页面</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">初始化</td>
<td>新页面入栈</td>
<td style="text-align: left">小程序打开的第一个页面</td>
<td style="text-align: left"></td>
<td style="text-align: left">onLoad, onShow</td>
</tr>
<tr>
<td style="text-align: left">打开新页面</td>
<td>新页面入栈</td>
<td style="text-align: left">调用 API wx.navigateTo <br>使用组件<navigator open-type="navigateTo"></navigator></td>
<td style="text-align: left">onHide</td>
<td style="text-align: left">onLoad, onShow</td>
</tr>
<tr>
<td style="text-align: left">页面重定向</td>
<td>当前页面出栈,新页面入栈</td>
<td style="text-align: left">调用 API wx.redirectTo <br>使用组件<navigator open-type="redirectTo"></navigator></td>
<td style="text-align: left">onUnload</td>
<td style="text-align: left">onLoad, onShow</td>
</tr>
<tr>
<td style="text-align: left">页面返回</td>
<td>页面不断出栈,直到目标返回页</td>
<td style="text-align: left">调用 API wx.navigateBack <br>使用组件<navigator open-type="navigateBack"> <br>用户按左上角返回按钮</navigator></td>
<td style="text-align: left">onUnload</td>
<td style="text-align: left">onShow</td>
</tr>
<tr>
<td style="text-align: left">Tab 切换</td>
<td>页面全部出栈,只留下新的 Tab 页面<br>如果从没有<code>tabBar</code>的页面跳转至有<code>tabBar</code>的页面就<code>一定要用这个</code>,而不是上面的,否则会报错</td>
<td style="text-align: left">调用 API wx.switchTab <br>使用组件<navigator open-type="switchTab"><br>用户切换 Tab</navigator></td>
<td style="text-align: left"></td>
<td style="text-align: left">各种情况请参考下表</td>
</tr>
<tr>
<td style="text-align: left">重启动</td>
<td>页面全部出栈,只留下新的页面</td>
<td style="text-align: left">调用 API wx.reLaunch <br>使用组件<navigator open-type="reLaunch"></navigator></td>
<td style="text-align: left">onUnload</td>
<td style="text-align: left">onLoad, onShow</td>
</tr>
</tbody>
</table>
<ol start="2">
<li>代码示例:</li>
</ol>
<pre><code class="language-jsx">wx.navigateTo({ //当前页面被隐藏,缓存在栈中,最多存放10个页面
        url: "/pages/posts/post" //跳转的页面路径
})
wx.redirectTo({ //当前页面被销毁
        url: "/pages/posts/post"
})

</code></pre>
<ol start="3">
<li>Tab 切换对应的生命周期(以 A、B 页面为 Tabbar 页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例):</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">当前页面</th>
<th style="text-align: left">路由后页面</th>
<th style="text-align: left">触发的生命周期(按顺序)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">A</td>
<td style="text-align: left">A</td>
<td style="text-align: left">Nothing happend</td>
</tr>
<tr>
<td style="text-align: left">A</td>
<td style="text-align: left">B</td>
<td style="text-align: left">A.onHide(), B.onLoad(), B.onShow()</td>
</tr>
<tr>
<td style="text-align: left">A</td>
<td style="text-align: left">B(再次打开)</td>
<td style="text-align: left">A.onHide(), B.onShow()</td>
</tr>
<tr>
<td style="text-align: left">C</td>
<td style="text-align: left">A</td>
<td style="text-align: left">C.onUnload(), A.onShow()</td>
</tr>
<tr>
<td style="text-align: left">C</td>
<td style="text-align: left">B</td>
<td style="text-align: left">C.onUnload(), B.onLoad(), B.onShow()</td>
</tr>
<tr>
<td style="text-align: left">D</td>
<td style="text-align: left">B</td>
<td style="text-align: left">D.onUnload(), C.onUnload(), B.onLoad(), B.onShow()</td>
</tr>
<tr>
<td style="text-align: left">D(从转发进入)</td>
<td style="text-align: left">A</td>
<td style="text-align: left">D.onUnload(), A.onLoad(), A.onShow()</td>
</tr>
<tr>
<td style="text-align: left">D(从转发进入)</td>
<td style="text-align: left">B</td>
<td style="text-align: left">D.onUnload(), B.onLoad(), B.onShow()</td>
</tr>
</tbody>
</table>
</blockquote>
<h3 id="ⅱ-tips">Ⅱ-Tips</h3>
<blockquote>
<ul>
<li><code>navigateTo</code>, <code>redirectTo</code> 只能打开非 tabBar 页面。</li>
<li><code>switchTab</code> 只能打开 tabBar 页面。</li>
<li><code>reLaunch</code> 可以打开任意页面。</li>
<li>页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。</li>
<li>调用页面路由带的参数可以在目标页面的<code>onLoad</code>中获取。</li>
<li><code>注意</code>:开发者可以使用 <code>getCurrentPages()</code> 函数获取当前页面栈</li>
<li>页面栈中最多存在<code>10</code>个</li>
</ul>
</blockquote>
<h2 id="2模块化">2、模块化</h2>
<blockquote>
<p>可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 <code>module.exports</code> 或者 <code>exports</code> 才能对外暴露接口。</p>
</blockquote>
<hr>
<h1 id="六组件与组件库">六、组件与组件库</h1>
<h2 id="1官方组件">1、官方组件</h2>
<blockquote>
<p>重点举例⼩程序中常⽤的布局组件 view,tex 等,现只举例部分,之后遇到觉得需要mark再写入,大部分可以看官方文档组件部分,便不太多赘述</p>
</blockquote>
<h3 id="ⅰ-view">Ⅰ-view</h3>
<blockquote>
<ol>
<li>在小程序中,通常使用<code>&lt;view/&gt;</code>代替<code>&lt;div/&gt;</code>作为容器来做布局</li>
</ol>
<pre><code class="language-xml">&lt;!--pages/welcome/welcome.wxml--&gt;
&lt;view class="container"&gt;
&lt;image class="avatar" src="/images/测试头像图片.jpg"&gt;&lt;/image&gt;
&lt;text&gt;Hello,洪jl&lt;/text&gt;
&lt;!-- &lt;button&gt;开启小程序之旅&lt;/button&gt; --&gt;
&lt;view&gt;
&lt;text&gt;开启小程序之旅&lt;/text&gt;
&lt;/view&gt;
&lt;/view&gt;

</code></pre>
</blockquote>
<h3 id="ⅱ-text">Ⅱ-text</h3>
<blockquote>
<ol>
<li>⽂本标签</li>
<li>只能嵌套text</li>
<li>⻓按⽂字可以复制(只有该标签有这个功能)--&gt;selectable</li>
<li>可以对如: <code>空格回车&amp;nbsp;</code> 进⾏编码--&gt;decode</li>
</ol>
<table>
<thead>
<tr>
<th>属性名</th>
<th>类型</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>selectable</td>
<td>Boolean</td>
<td>false</td>
<td>⽂本是否可选</td>
</tr>
<tr>
<td>decode</td>
<td>Boolean</td>
<td>false</td>
<td>是否解码</td>
</tr>
</tbody>
</table>
<pre><code class="language-jsx">&lt;text selectable="{{false}}" decode="{{false}}"&gt;
普&amp;nbsp;通
&lt;/text&gt;

</code></pre>
</blockquote>
<h3 id="ⅲ-image">Ⅲ-image</h3>
<blockquote>
<ol>
<li>图⽚标签,image组件<code>默认</code>宽度320px、⾼度240px,所以如果不进行宽高设置,不会进行自适应</li>
<li>⽀持懒加载</li>
</ol>
<table>
<thead>
<tr>
<th>属性名</th>
<th>类型</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>src</td>
<td>String</td>
<td></td>
<td>图⽚资源地址</td>
</tr>
<tr>
<td>mode</td>
<td>String</td>
<td><code>scaleToFill</code></td>
<td>图⽚裁剪、缩放的模式</td>
</tr>
<tr>
<td>lazy-load</td>
<td>Boolean</td>
<td>false</td>
<td>图⽚懒加载</td>
</tr>
</tbody>
</table>
<ol start="3">
<li><code>mode</code>模式列举:</li>
</ol>
<table>
<thead>
<tr>
<th>模式</th>
<th>值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>缩放</td>
<td>scaleToFill</td>
<td>不保持纵横⽐缩放图⽚,使图⽚的宽⾼完全拉伸⾄填满image 元素</td>
</tr>
<tr>
<td>缩放</td>
<td>aspectFit</td>
<td>保持纵横⽐缩放图⽚,使图⽚的⻓边能完全显⽰出来。</td>
</tr>
<tr>
<td>缩放</td>
<td>aspectFill</td>
<td>保持纵横⽐缩放图⽚,只保证图⽚的短边能完全显⽰出来</td>
</tr>
<tr>
<td>缩放</td>
<td>widthFix</td>
<td>宽度不变,⾼度⾃动变化,保持原图宽⾼⽐不变</td>
</tr>
<tr>
<td>裁剪</td>
<td>top</td>
<td>不缩放图⽚,只显⽰图⽚的顶部区域</td>
</tr>
<tr>
<td>裁剪</td>
<td>bottom</td>
<td>不缩放图⽚,只显⽰图⽚的底部区域</td>
</tr>
<tr>
<td>裁剪</td>
<td>center</td>
<td>不缩放图⽚,只显⽰图⽚的中间区域</td>
</tr>
<tr>
<td>裁剪</td>
<td>left</td>
<td>不缩放图⽚,只显⽰图⽚的左边区域</td>
</tr>
<tr>
<td>裁剪</td>
<td>right</td>
<td>不缩放图⽚,只显⽰图⽚的右边区域</td>
</tr>
<tr>
<td>裁剪</td>
<td><code>top left</code>、<code>top right</code><br><code>bottom left</code>、<code>bottom right</code></td>
<td>不缩放图⽚,只显示值所指向区域</td>
</tr>
</tbody>
</table>
<ol start="4">
<li>代码示例:</li>
</ol>
<pre><code class="language-jsx">&lt;image class="avatar"mode="aspectFit" src="/images/测试头像图片.jpg"&gt;&lt;/image&gt;

</code></pre>
<ol start="5">
<li>
<p>应用场景举例,简单效果对比</p>
<ol>
<li>使用默认mode效果 --&gt;会将图片进行拉伸,导致图片变形</li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216201040777-787097231.png"></p>
<ol start="2">
<li>设置为<code>aspectFill</code>效果 --&gt;保持纵横⽐缩放图⽚,只保证图⽚的短边能完全显⽰出来,图片不会变形</li>
</ol>
</li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216201215286-1520669105.png"></p>
<ol start="3">
<li>根据不同的场景选择不同的<code>mode</code>才是最正确的,就如同该截图场景中,<code>aspectFill</code>明显优于默认</li>
</ol>
</blockquote>
<h3 id="ⅳ-swiper">Ⅳ-swiper</h3>
<blockquote>
<p>滑块<code>视图容器</code>。其中只可放置swiper-item组件,否则会导致未定义的行为。</p>
<ol>
<li>代码示例</li>
</ol>
<pre><code class="language-jsx">&lt;!--pages/posts/posts.wxml--&gt;
&lt;view&gt;
&lt;!--
//1. "false" ==true 普通字符串
//    "{{false}}"==false   {{}}视作运算标记,里面的内容表示表达式
//2. 当你的属性为true时,可以省略value值-- indicator-dots="{{true}}" == indicator-dots
--&gt;
&lt;swiper indicator-dots="{{true}}" autoplay interval="2000" duration="1000" vertical circular&gt;
&lt;swiper-item&gt;
    &lt;!-- 插槽 --&gt;
    &lt;image mode="scaleToFill" src="/images/1.jpg"&gt;&lt;/image&gt;
&lt;/swiper-item&gt;
&lt;swiper-item&gt;
    &lt;!-- 插槽 --&gt;
    &lt;image mode="scaleToFill" src="/images/2.jpg"&gt;&lt;/image&gt;
&lt;/swiper-item&gt;
&lt;swiper-item&gt;
    &lt;!-- 插槽 --&gt;
    &lt;image mode="scaleToFill" src="/images/3.jpg"&gt;&lt;/image&gt;
&lt;/swiper-item&gt;
&lt;/swiper&gt;
&lt;/view&gt;

</code></pre>
<ol start="2">
<li>该轮播图代码效果预览:<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216201252980-941104185.gif"></li>
</ol>
</blockquote>
<h3 id="ⅴ-scroll-view">Ⅴ-scroll-view</h3>
<blockquote>
<p>可滚动视图区域。使用竖向滚动时,需要给scroll-view一个固定高度,通过 WXSS 设置 height。组件属性的长度单位默认为px,2.4.0起支持传入单位(rpx/px)。</p>
<ol>
<li>使用举例图</li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216201331817-204899974.png"></p>
</blockquote>
<h2 id="2linui组件库">2、LinUi组件库</h2>
<h3 id="ⅰ-安装与使用">Ⅰ-安装与使用</h3>
<blockquote>
<ol>
<li><code>Lin UI</code> 是基于 <strong>微信小程序原生语法</strong> 实现的组件库。遵循简洁,易用的设计规范。</li>
<li>与其他组件库不同的是,除了提供基本的组件外,还会提供 <code>wxs模块</code> 、<code>高级组件</code> 、 <code>电商组件模块</code> 等等。 例如,在电商项目里常用的 <code>SKU联动选择</code> ,<code>城市选择器</code> 等</li>
<li><code>安装</code>过程可看官方文档:</li>
</ol>
<ol>
<li>打开小程序的项目根目录,执行下面的命令(如果使用了云开发,需要进入miniprogram文件夹下执行下面的命令)</li>
</ol>
<pre><code class="language-sh">npm init
/*注意事项
1.执行npm init进行初始化,此时会生成一个package.json文件,如果不进行npm init,在构建npm的时候会报一个错误:没有找到 node_modules 目录
2.不建议使用cnpm,这样会带来一些未知的错误。如果网络情况不佳,可以使用下面的命令行更换为淘宝源。
npm config set registry https://registry.npm.taobao.org */

</code></pre>
<p>2)继续执行下面的命令</p>
<pre><code class="language-sh">npm install lin-ui

</code></pre>
<ol start="4">
<li>安装完成后在小程序需要点击<code>工具</code>--&gt;<code>构建 npm</code>才可以使用(<code>所有npm引入的都需要这一步</code>)</li>
<li>要使用<code>自定义组件</code>的话,需要在<code>配置.json</code>文件中(可以在全局的也可以在页面的,作用域不同)注册,具体实现看下面示例</li>
</ol>
</blockquote>
<h3 id="ⅱ-avatar头像">Ⅱ-avatar头像</h3>
<blockquote>
<ol>
<li>要使用<code>自定义组件</code>的话,需要在当前page页面.json文件中注册</li>
</ol>
<pre><code class="language-json">//page.json
{
"usingComponents": {
"l-avatar":"/miniprogram_npm/lin-ui/avatar/index",
"组件名(可以自取,一般如果是linui,就l-xxx)":"构建后的路径--要具体到那个文件夹下的js"
}
}

</code></pre>
<ol start="2">
<li>使用:</li>
</ol>
<pre><code class="language-jsx">&lt;!--pages/welcome/welcome.wxml--&gt;
&lt;view class="container"&gt;
&lt;!-- &lt;image class="avatar" lazy-load="true" mode="aspectFit" src="/images/测试头像图片.jpg"&gt;&lt;/image&gt; --&gt;
&lt;l-avatar
class="l-avatar"
placement="bottom"
open-data="{{['userAvatarUrl','userNickName']}}"
size="200"
/&gt;
&lt;/view&gt;

/* pages/welcome/welcome.wxss */
//可以自己写样式类,加到组件上
.l-avatar{
margin-top: 160rpx;
}

</code></pre>
</blockquote>
<h3 id="ⅲ-icon">Ⅲ-icon</h3>
<blockquote>
<ol>
<li>在当前page页面.json文件中注册</li>
</ol>
<pre><code class="language-json">{
"usingComponents": {
"l-icon":"/miniprogram_npm/lin-ui/icon/index"
}
}

</code></pre>
<ol start="2">
<li>使用</li>
</ol>
<pre><code class="language-jsx">&lt;l-icon size="20" color="#34bfa3" name="cart"&gt;&lt;/l-icon&gt;
&lt;l-icon name="research"&gt;&lt;/l-icon&gt;

</code></pre>
</blockquote>
<hr>
<h1 id="七小程序api">七、小程序API</h1>
<h2 id="1数据缓存">1、数据缓存</h2>
<blockquote>
<p>类似于网页的<code>localStorage</code></p>
<p>官方文档很详细,此处给出具体地址,翻阅文档即可</p>
</blockquote>
<h2 id="2交互">2、交互</h2>
<blockquote>
<p>一些微信官方给出的组件,具体参数解释看文档,以下给出学习过程中代码示例</p>
</blockquote>
<h3 id="ⅰ-wxshowtoast与wxshowmodal">Ⅰ-wx.showToast与wx.showModal</h3>
<blockquote>
<ol>
<li><code>wx.showToast</code>代码示例:</li>
</ol>
<pre><code class="language-js">wx.showToast({
    //此处其实已经被修改完状态,才开始提示,所以要反过来
    title: this.data.collected ? '收藏成功' : '取消收藏',
    duration: 1000
})

</code></pre>
<ol start="2">
<li><code>wx.showModal</code>代码示例:</li>
</ol>
<pre><code class="language-js">async onCollect(e) {
const result = await wx.showModal({
    title:!this.data.collected ? '进行收藏' : '取消收藏',
})
if (!result.confirm) return; //点击取消退出
   .......//点击确认后运行的代码
    wx.showToast({
    //此处其实已经被修改完状态,才开始提示,所以要反过来
    title: this.data.collected ? '收藏成功' : '取消收藏',
    duration: 1000
})
},

</code></pre>
<ol start="3">
<li>运行效果示例(两者并存的效果):<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216201700047-451151807.gif"></li>
</ol>
</blockquote>
<h2 id="3媒体">3、媒体</h2>
<h3 id="ⅰ-媒体音乐播放">Ⅰ-媒体音乐播放</h3>
<blockquote>
<ol>
<li>wx.getBackgroundAudioManager--播放音乐</li>
<li>代码示例</li>
</ol>
<pre><code class="language-js">const app = getApp() //此处keyi
onLoad: function (options) {
const mgr = wx.getBackgroundAudioManager()
this.data._mgr = mgr
// if(app.gIsPlayMusic) {此处进入即默认播放
//   mgr.src = this.data.postData.music.url
//   mgr.title = this.data.postData.music.title
// }

mgr.onPlay(() =&gt; {
   console.log("监听播放")
})
mgr.onPause(() =&gt; {
   console.log("监听暂停")
})
}
/**
    * 音乐播放
*/
onMusic() {
const mgr = this.data._mgr
if (this.data.isPlaying) {
   mgr.pause()
   app.gIsPlayMusicId = -1
} //当前播放状态如果为true则终止(stop())、pause()暂停
else {
   mgr.src = this.data.postData.music.url//此处为播放
   mgr.title = this.data.postData.music.title
   app.gIsPlayMusicId = this.data._pid
}

this.setData({
   isPlaying: !this.data.isPlaying
})
},

</code></pre>
</blockquote>
<h3 id="ⅱ-图片">Ⅱ-图片</h3>
<h4 id="1-wxpreviewimageobject-object">1) wx.previewImage(Object object)</h4>
<blockquote>
<p>在新页面中全屏预览图片。预览的过程中用户可以进行保存图片、发送给朋友等操作</p>
<ol>
<li>代码示例</li>
</ol>
<pre><code class="language-jsx">&lt;!--pages/movie-detail/movie-detail.wxml--&gt;
&lt;image catch:tap="onViewPost" class="movie-img" src="{{movie.images}}"&gt;&lt;/image&gt;
// pages/movie-detail/movie-detail.js
onViewPost(e) { //相册功能(预览)
    wx.previewImage({
      urls: ,
    })
},

</code></pre>
<ol start="2">
<li>详见开发文档</li>
</ol>
</blockquote>
<h2 id="4界面">4、界面</h2>
<h3 id="ⅰ-tab-bar">Ⅰ-Tab Bar</h3>
<blockquote>
<p>使用时在app.json中进行配置即可,相关配置详情看全局配置文档,如果需要进行相应操作看官方文档</p>
<pre><code class="language-json">"tabBar": {
"selectedColor": "#333333",
"color": "#999999",
"borderStyle": "black",
"position": "top",
"list": [
{
   "pagePath": "pages/posts/posts",
   "text": "阅读",
   "iconPath": "/images/tabBar/yuedu.png",
   "selectedIconPath": "/images/tabBar/yuedu_1.png"
},
{
   "pagePath": "pages/movies/movies",
   "text": "电影",
   "iconPath": "/images/tabBar/dianying_1.png",
   "selectedIconPath": "/images/tabBar/dianying.png"
}
]
}

</code></pre>
</blockquote>
<hr>
<h1 id="八小程序生命周期">八、小程序生命周期</h1>
<blockquote>
<p>分为<code>应⽤⽣命周期</code>和<code>⻚⾯⽣命周期</code></p>
<p>关于小程序前后台的定义和小程序的运行机制,请参考运行机制章节。</p>
</blockquote>
<h2 id="1应用生命周期">1、应用生命周期</h2>
<blockquote>
<ol>
<li>应用生命周期表</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">必填</th>
<th style="text-align: left">说明</th>
<th>场景</th>
<th style="text-align: left">最低版本</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">onLaunch</td>
<td style="text-align: left">function</td>
<td style="text-align: left">否</td>
<td style="text-align: left">生命周期回调——监听小程序初始化。</td>
<td>小程序初始化完成时触发,全局只触发一次。参数也可以使用 wx.getLaunchOptionsSync 获取。</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">onShow</td>
<td style="text-align: left">function</td>
<td style="text-align: left">否</td>
<td style="text-align: left">生命周期回调——监听小程序启动或切前台。</td>
<td>小程序启动,或从后台进入前台显示时触发。也可以使用 wx.onAppShow 绑定监听</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">onHide</td>
<td style="text-align: left">function</td>
<td style="text-align: left">否</td>
<td style="text-align: left">生命周期回调——监听小程序切后台。</td>
<td>小程序从前台进入后台时触发。也可以使用 wx.onAppHide 绑定监听</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">onError</td>
<td style="text-align: left">function</td>
<td style="text-align: left">否</td>
<td style="text-align: left">错误监听函数。</td>
<td>小程序发生脚本错误或 API 调用报错时触发。也可以使用 wx.onError 绑定监听</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left">onPageNotFound</td>
<td style="text-align: left">function</td>
<td style="text-align: left">否</td>
<td style="text-align: left">页面不存在监听函数。</td>
<td>小程序要打开的页面不存在时触发。也可以使用 wx.onPageNotFound 绑定监听。</td>
<td style="text-align: left">1.9.90</td>
</tr>
<tr>
<td style="text-align: left">onUnhandledRejection</td>
<td style="text-align: left">function</td>
<td style="text-align: left">否</td>
<td style="text-align: left">未处理的 Promise 拒绝事件监听函数。</td>
<td>小程序有未处理的 Promise 拒绝时触发。也可以使用 wx.onUnhandledRejection 绑定监听</td>
<td style="text-align: left">2.10.0</td>
</tr>
<tr>
<td style="text-align: left">onThemeChange</td>
<td style="text-align: left">function</td>
<td style="text-align: left">否</td>
<td style="text-align: left">监听系统主题变化</td>
<td>系统切换主题时触发。也可以使用 wx.onThemeChange 绑定监听</td>
<td style="text-align: left">2.11.0</td>
</tr>
<tr>
<td style="text-align: left">其他</td>
<td style="text-align: left">any</td>
<td style="text-align: left">否</td>
<td style="text-align: left">开发者可以添加任意的函数或数据变量到 <code>Object</code> 参数中,用 <code>this</code> 可以访问</td>
<td></td>
<td style="text-align: left"></td>
</tr>
</tbody>
</table>
<ol start="2">
<li>代码示例:</li>
</ol>
<pre><code class="language-jsx">App({
onLaunch (options) {
// Do something initial when launch.
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
},
globalData: 'I am global data'
,
onPageNotFound(res) {
       wx.redirectTo({
       url: 'pages/...'
       }) // 如果是 tabbar 页面,请使用 wx.switchTab
}

})

</code></pre>
</blockquote>
<h2 id="2页面生命周期">2、页面生命周期</h2>
<blockquote>
<ol>
<li>页面生命周期表</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align: left">属性</th>
<th style="text-align: left">类型</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">data</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">页面的初始数据</td>
</tr>
<tr>
<td style="text-align: left">options</td>
<td style="text-align: left">Object</td>
<td style="text-align: left">页面的组件选项,同 <code>Component</code> 构造器 中的 <code>options</code> ,需要基础库版本 2.10.1</td>
</tr>
<tr>
<td style="text-align: left">onLoad</td>
<td style="text-align: left">function</td>
<td style="text-align: left">生命周期回调—监听页面加载</td>
</tr>
<tr>
<td style="text-align: left">onShow</td>
<td style="text-align: left">function</td>
<td style="text-align: left">生命周期回调—监听页面显示</td>
</tr>
<tr>
<td style="text-align: left">onReady</td>
<td style="text-align: left">function</td>
<td style="text-align: left">生命周期回调—监听页面初次渲染完成</td>
</tr>
<tr>
<td style="text-align: left">onHide</td>
<td style="text-align: left">function</td>
<td style="text-align: left">生命周期回调—监听页面隐藏</td>
</tr>
<tr>
<td style="text-align: left">onUnload</td>
<td style="text-align: left">function</td>
<td style="text-align: left">生命周期回调—监听页面卸载</td>
</tr>
<tr>
<td style="text-align: left">onPullDownRefresh</td>
<td style="text-align: left">function</td>
<td style="text-align: left">监听用户下拉动作</td>
</tr>
<tr>
<td style="text-align: left">onReachBottom</td>
<td style="text-align: left">function</td>
<td style="text-align: left">页面上拉触底事件的处理函数</td>
</tr>
<tr>
<td style="text-align: left">onShareAppMessage</td>
<td style="text-align: left">function</td>
<td style="text-align: left">用户点击右上角转发</td>
</tr>
<tr>
<td style="text-align: left">onShareTimeline</td>
<td style="text-align: left">function</td>
<td style="text-align: left">用户点击右上角转发到朋友圈</td>
</tr>
<tr>
<td style="text-align: left">onAddToFavorites</td>
<td style="text-align: left">function</td>
<td style="text-align: left">用户点击右上角收藏</td>
</tr>
<tr>
<td style="text-align: left">onPageScroll</td>
<td style="text-align: left">function</td>
<td style="text-align: left">页面滚动触发事件的处理函数</td>
</tr>
<tr>
<td style="text-align: left">onResize</td>
<td style="text-align: left">function</td>
<td style="text-align: left">页面尺寸改变时触发,详见 响应显示区域变化</td>
</tr>
<tr>
<td style="text-align: left">onTabItemTap</td>
<td style="text-align: left">function</td>
<td style="text-align: left">当前是 tab 页时,点击 tab 时触发</td>
</tr>
<tr>
<td style="text-align: left">其他</td>
<td style="text-align: left">any</td>
<td style="text-align: left">开发者可以添加任意的函数或数据到 <code>Object</code> 参数中,在页面的函数中用 <code>this</code> 可以访</td>
</tr>
</tbody>
</table>
<ol start="2">
<li>官方的小程序页面生命周期图:</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216201901046-776617737.png">
</blockquote>
<h2 id="3组件生命周期-不算在小程序生命周期中">3、组件生命周期-不算在小程序生命周期中</h2>
<blockquote>
<p>组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发</p>
</blockquote>
<hr>
<h1 id="九自定义组件">九、自定义组件</h1>
<blockquote>
<p>开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似</p>
<p>这部分将截取文档自定义组件部分中常见的部分进行注解</p>
</blockquote>
<h2 id="1组件模板和样式">1、组件模板和样式</h2>
<blockquote>
<p>类似于页面,自定义组件拥有自己的 <code>wxml</code> 模板和 <code>wxss</code> 样式。</p>
</blockquote>
<h3 id="ⅰ-组件样式">Ⅰ-组件样式</h3>
<blockquote>
<p>组件对应 <code>wxss</code> 文件的样式,只对组件wxml内的节点生效。编写组件样式时,需要注意以下几点:</p>
<ul>
<li>组件和引用组件的页面不能使用id选择器(<code>#a</code>)、属性选择器(<code></code>)和标签名选择器,请改用class选择器。</li>
<li>组件和引用组件的页面中使用后代选择器(<code>.a .b</code>)在一些极端情况下会有非预期的表现,如遇,请避免使用。</li>
<li>子元素选择器(<code>.a&gt;.b</code>)只能用于 <code>view</code> 组件与其子节点之间,用于其他组件可能导致非预期的情况。</li>
<li>继承样式,如 <code>font</code> 、 <code>color</code> ,会从组件外继承到组件内。</li>
<li>除继承样式外, <code>app.wxss</code> 中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)。</li>
</ul>
<pre><code class="language-css">#a { } /* 在组件中不能使用 */
{ } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a &gt; .b { } /* 除非 .a 是 view 组件节点,否则不一定会生效 */

</code></pre>
<p>除此以外,组件可以指定它所在节点的默认样式,使用 <code>:host</code> 选择器(需要包含基础库 1.7.2 或更高版本的开发者工具支持)。</p>
<p>注:此处本人出了一个<code>问题</code>,详见---&gt;本笔记的<code>杂记-&gt;初学者阶段遇到的问题与解决-&gt;Ⅶ</code></p>
</blockquote>
<h3 id="ⅱ-外部样式类">Ⅱ-外部样式类</h3>
<blockquote>
<ol>
<li>有时,组件希望接受外部传入的样式类。此时可以在 <code>Component</code> 中用 <code>externalClasses</code> 定义段定义若干个外部样式类。这个特性可以用于实现类似于 <code>view</code> 组件的 <code>hover-class</code> 属性:页面可以提供一个样式类,赋予 <code>view</code> 的 <code>hover-class</code> ,这个样式类本身写在页面中而非 <code>view</code> 组件的实现中。</li>
</ol>
<p><strong>注意:在同一个节点上使用普通样式类和外部样式类时,两个类的<code>优先级是未定义</code>的,因此最好避免这种情况。</strong></p>
<ol start="2">
<li>
<p><strong>代码示例:</strong></p>
<ol>
<li>自定义组件部分定义与占位符示例</li>
</ol>
<pre><code class="language-xaml">/* 组件 custom-component.js */
Component({
externalClasses: ['my-class']
})
                                                                  
&lt;!-- 组件 custom-component.wxml 如何引用 --&gt;
&lt;custom-component class="my-class"&gt;这段文本的颜色由组件外的 class 决定&lt;/custom-component&gt;                                 

</code></pre>
<p>这样,组件的使用者可以指定这个样式类对应的 class ,就像使用普通属性一样。在 2.7.1 之后,可以指定多个对应的 class 。</p>
</li>
<li>
<p>外部使用自定义组件并传入样式类</p>
</li>
</ol>
<pre><code class="language-xaml"> &lt;!-- 页面的 WXML --&gt;
&lt;custom-component my-class="red-text" /&gt;
&lt;custom-component my-class="large-text" /&gt;
&lt;!-- 以下写法需要基础库版本 2.7.1 以上注意 这只是一个组件传入两个类名,而不是分别创建两个组件--&gt;
&lt;custom-component my-class="red-text large-text" /&gt;
                                                                                                               
------------ 样式类声明 页面.wxss ---------------------------------
.red-text {
   color: red;
}
.large-text {
   font-size: 1.5em;
}

</code></pre>
<ol start="3">
<li>
<p>主要用途:</p>
<ol>
<li>如果子组件都是我们自己开发的,而且无所谓改动自定义组件源码,那可以不使用这个</li>
<li>如果自定义组件封装已经足够成熟,不想再动其中样式源码,就可以用外部样式类进行对自定义组件样式改变(使用<code>!important</code>属性能将样式优先级提高),以此进行对于封装好的组件的样式修改,同理可以运用于第三方库</li>
</ol>
<pre><code class="language-css">.movielist{ //外部样式类
margin-bottom: 25rpx;
background-color: #fff !important;//此处就可以将这个样式提升到自定义组件样式优先级之上
}

</code></pre>
</li>
<li>
<p>以后如果自己封装自定义组件,就可以向外暴露外部样式类</p>
</li>
</ol>
</blockquote>
<h2 id="2组件间通信与事件">2、组件间通信与事件</h2>
<h3 id="ⅰ-组件间通信">Ⅰ-组件间通信</h3>
<blockquote>
<p>组件间的基本通信方式有以下几种。</p>
<ul>
<li>WXML 数据绑定:用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容数据(自基础库版本 2.0.9 开始,还可以在数据中包含函数)。具体在 组件模板和样式 章节中介绍。</li>
<li>事件:用于子组件向父组件传递数据,可以传递任意数据。</li>
<li>如果以上两种方式不足以满足需要,父组件还可以通过 <code>this.selectComponent</code> 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。</li>
</ul>
</blockquote>
<h3 id="ⅱ-触发事件">Ⅱ-触发事件</h3>
<blockquote>
<p>自定义组件触发事件时,需要使用 <code>triggerEvent</code> 方法,指定事件名、detail对象和事件选项</p>
<ol>
<li>官方代码示例</li>
</ol>
<pre><code class="language-jsx">&lt;!-- 在自定义组件中 --&gt;
&lt;button bindtap="onTap"&gt;点击这个按钮将触发“myevent”事件&lt;/button&gt;
//js文件中
Component({
properties: {},
methods: {
onTap: function(){
    var myEventDetail = {} // detail对象,提供给事件监听函数
    var myEventOption = {} // 触发事件的选项
    this.triggerEvent('myevent', myEventDetail, myEventOption)
}
}
})

</code></pre>
<ol start="2">
<li>本人在<code>hello小程序</code>源码中应用</li>
</ol>
<pre><code class="language-jsx">&lt;!--pages/posts/posts.wxml--&gt;
&lt;block wx:for="{{posts}}" wx:for-item="item" wx:key="postId" wx:for-index="index"&gt;
&lt;post bind:posttap="onGoDetail" res="{{item}}" /&gt;
&lt;/block&gt;
// components/posts/index.js这是自定义组件

methods: {
onTap (e) {//此处不能用箭头函数,否则`this.triggerEvent`将会找不到报错
const pid = this.data.res.postId
// console.log( this.data)
// console.log( this.properties)
    this.triggerEvent('posttap',{
      pid   //这个参数会在事件调用处获取到
    })
},
}

// pages/posts/posts.js这个是在调用自定义组件的页面的js中,即可以使用自己的方法,单纯是调用自定义组件定义的事件
onGoDetail: (e) =&gt; { //获取组件的自定义属性
//先判断,如果e.currentTarget.dataset去得到值,就取有值的 下面这3种写法效果等同
//let pid = (e.currentTarget.dataset.id)?e.currentTarget.dataset.id:e.detail.pid
// let pid = e.detail.pid|e.currentTarget.dataset.id
let pid = e.detail.pid || e.currentTarget.dataset.id
wx.navigateTo({
    url: '/pages/post-detail/post-detail?pid=' + pid,
})

</code></pre>
</blockquote>
<hr>
<h1 id="杂记">杂记</h1>
<blockquote>
<p>体系学习过程笔记外的知识点</p>
</blockquote>
<h2 id="1微信开发者工具使用技巧">1、微信开发者工具使用技巧</h2>
<h3 id="ⅰ-新建页面的技巧与规则">Ⅰ-新建页面的技巧与规则:</h3>
<blockquote>
<ol>
<li>本技巧适用于<code>微信开发者工具</code></li>
<li>当你需要新建一个页面时:新建一个page文件目录--&gt;右键<code>新建page</code>--&gt;输入page名字--&gt;一次生成所需四个文件 且自动注册到<code>app.json</code>中</li>
<li>
<h2 id="如果配置文件中出现错误时自动新建无法成功更无法自动注册">如果配置文件中出现错误时,自动新建无法成功,更无法自动注册</h2>
</li>
</ol>
</blockquote>
<h3 id="ⅱ-指定初始页面">Ⅱ-指定初始页面</h3>
<blockquote>
<p>当你写多个page时,如果每次通过修改<code>app.json</code>的配置项来指定初始页面,十分麻烦</p>
<ol>
<li>可以在<code>app.json</code>用"entryPagePath":"pages/页面文件夹/页面文件名" 配置首页,但仍要修改配置文件,十分麻烦</li>
<li>使用编译器的<code>工具栏</code>--&gt;添加<code>编译模式</code>进行指定初始化页面(启动页面默认值要先删除才有提示)</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216202359938-2006675935.png">
<ol start="3">
<li>添加后每次调试只要<code>选择编译模式</code>,就可以切换初始页面</li>
</ol>
</blockquote>
<h3 id="ⅲ-ctrl滚轮缩放工具界面">Ⅲ-ctrl+滚轮缩放工具界面</h3>
<blockquote>
<p>只能调成字体了,<code>这个BUG被修复了</code>🐶<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216202502949-1757414029.png"></p>
</blockquote>
<h2 id="2微信开发常见编程方法与细节">2、微信开发常见编程方法与细节</h2>
<blockquote>
<p>学习、练习、开发微信小程序过程中遇到的一些基础知识与细节记录</p>
</blockquote>
<h3 id="ⅰ-相对路径规则">Ⅰ-相对路径规则:</h3>
<blockquote>
<ol>
<li><code>/</code>代表根目录:如引入根目录下的images/图片</li>
</ol>
<pre><code class="language-xml">&lt;image src="/images/测试头像图片.jpg"&gt;&lt;/image&gt;

</code></pre>
<ol start="2">
<li>其余的如:<code>../</code>上一级目录、<code>./</code>同级目录,都与一般无异</li>
</ol>
</blockquote>
<h3 id="ⅱ-npm引入第三方库后需进行构建">Ⅱ-npm引入第三方库后需进行构建</h3>
<blockquote>
<p>安装第三方库后在小程序需要点击<code>工具</code>--&gt;<code>构建 npm</code>才可以使用</p>
<p><code>所有npm引入的都需要这一步</code></p>
</blockquote>
<h2 id="3初学阶段遇到的问题与解决">3、初学阶段遇到的问题与解决</h2>
<blockquote>
<p>这部分将记录本人初学小程序过程遇到的问题,这部分应该大部分是小程序初学者才会遇到的,或者是本人虽然可以直接解决但觉得别人可能会遇到的便记录下来。而后续进阶阶段或者实战开发时遇到的问题,将记录在下面另一章节</p>
</blockquote>
<h3 id="ⅰ-设置整个page的背景色">Ⅰ-设置整个page的背景色</h3>
<blockquote>
<ol>
<li>问题:当我设置页面背景色时,发现添加背景色的page的高度是被内容撑起而不是全屏?如何解决最简单<br>
问题截图<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216202551380-1999494608.png"><br>
解决后<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216202707361-1340275251.png"></li>
</ol>
<p>解决:可以在你需要修改的page的样式文件中,给<code>&lt;page/&gt;</code>标签加样式,默认小程序是使用<page>作为最外层的</page></p>
<pre><code class="language-css">page{
background-color: #b3d4db;
}

</code></pre>
</blockquote>
<h3 id="ⅱ-小程序中使用less">Ⅱ-小程序中使用less</h3>
<blockquote>
<p>原⽣⼩程序不⽀持 less ,其他基于⼩程序的框架⼤体都⽀持,如 wepy , mpvue , taro 等。 但是仅仅因为⼀个less功能,⽽去引⼊⼀个框架,肯定是不可取的。因此可以⽤以下⽅式来实现</p>
<ol>
<li>编辑器是<code>vscode</code></li>
<li>安装插件<code>easy less</code></li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216202759526-1120784339.png"></p>
<ol start="3">
<li>在vscode的设置中加⼊如下,配置</li>
</ol>
<pre><code class="language-json">"less.compile": {
      "outExt": ".wxss"
}

</code></pre>
<ol start="4">
<li>在要编写样式的地⽅,新建 less ⽂件,如 index.less ,然后正常编辑即可。</li>
</ol>
</blockquote>
<h3 id="ⅲ-报错-typeerror-wxgetmenubuttonboundingclientrect-is-not-a-function">Ⅲ-报错: <code>TypeError: wx.getMenuButtonBoundingClientRect is not a function</code></h3>
<blockquote>
<p>控制台报错: <code>TypeError: wx.getMenuButtonBoundingClientRect is not a function</code></p>
<p>问题分析:这个 api是 更高版本版本支持的,你的用户有的客户端基础库版本 小于这个基础库。你在小程序后台设置下 最低基础库2.1.0.那样用户客户端基础库版本低于此就会提示升级</p>
<p>解决:<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216202852494-799644121.png"></p>
</blockquote>
<h3 id="ⅳ-警告无效的pagejson">Ⅳ-警告:<code>无效的page.json</code></h3>
<blockquote>
<p>这是初学者才会犯下的错误,但也记录下来</p>
<ol>
<li>问题:在page.json配置文件中与要修改导航栏颜色,却发生报错<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203001661-53474219.png"></li>
<li>解决:修改相应报错配置(翻阅文档),虽然响应的属性值相同,但一个外层包裹window,另一个没有包裹<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203049012-967582487.png"></li>
</ol>
</blockquote>
<h3 id="ⅴ-报错typeerror-cannot-read-property-mark-of-undefined">Ⅴ-报错:<code>typeError: Cannot read property 'mark' of undefined</code></h3>
<blockquote>
<ol>
<li>报错</li>
</ol>
<p>​        <img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203214381-1809875286.png"></p>
<ol start="2">
<li>解决:最终发现是小程序工具设置问题</li>
</ol>
<p>需要勾选增强编译<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203313722-448296213.png"></p>
</blockquote>
<h3 id="ⅵ-微信小程序中使用箭头函数导致this指向错误的问题">Ⅵ-微信小程序中使用箭头函数导致this指向错误的问题</h3>
<blockquote>
<ol>
<li>问题代码截图:</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203406890-1711631489.png">
<ol start="2">
<li>问题分析:</li>
</ol>
<p>众所周知,箭头函数<code>会改变this指向</code>,当我使用箭头函数后,函数中的this不再指向实例而是指向函数本身,导致data其实是找不到的发生报错</p>
<ol start="3">
<li>问题解决:
<ol>
<li>不使用箭头函数:</li>
</ol>
</li>
</ol>
<pre><code class="language-jsx">   async onCollect(e) {
      const result = await wx.showModal({
          title:!this.data.collected ? '进行收藏' : '取消收藏',
      })
      if (!result.confirm) return;

      let postCollected = this.data._postCollected //将当前data中(相当于之前本地缓存的postCollected)拉去下来,防止被覆盖
      postCollected = !this.data.collected
      this.setData({
          collected: !this.data.collected
      })
      wx.setStorageSync('posts_collected', postCollected)
      wx.showToast({
          //此处其实已经被修改完状态,才开始提示,所以要反过来
          title: this.data.collected ? '收藏成功' : '取消收藏',
          duration: 1000
      })
      },

</code></pre>
<ol start="2">
<li>使用箭头函数,但需要保存this指向</li>
</ol>
<pre><code class="language-js">    let con//用来保存this指向
                                                                              
    Page({
      //1. 生命周期函数中保存this指向
    onLoad: function (options) {
              con=this//用来保存this指向
    },
      //2. 函数体写法
    onCollect:async (e)=&gt; {箭头函数写法,需要保存this指向
       console.log(con)
      const result = await wx.showModal({
      title:!con.data.collected ? '进行收藏' : '取消收藏',
      })
      if (!result.confirm) return;
                                                                              
      let postCollected = con.data._postCollected //将当前data中(相当于之前本地缓存的postCollected)拉去下来,防止被覆盖
      postCollected = !con.data.collected
      con.setData({
      collected: !con.data.collected
      })
      wx.setStorageSync('posts_collected', postCollected)
      wx.showToast({
      //此处其实已经被修改完状态,才开始提示,所以要反过来
      title: con.data.collected ? '收藏成功' : '取消收藏',
      duration: 1000
      })
    })

</code></pre>
</blockquote>
<h3 id="ⅶ-警告-some-selectors-are-not-allowed-in-component-wxss-including-tag-name-selectors-id-selectors-and-attribute-selectors">Ⅶ-警告: <code>Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors</code></h3>
<blockquote>
<ol>
<li>出现场景:在我将之前写好的样式模块抽出成<code>自定义组件</code>时,控制台突然出现警告</li>
</ol>
<p><img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203510570-1735466690.png"></p>
<ol start="2">
<li>分析:我使用了<code>属性选择器</code>,而官方文档在自定义组件部分有要求不能使用,防止出现样式错误,</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203556629-1447475336.png)">
</blockquote>
<blockquote>
<ol start="3">
<li>解决:将属性选择器删除即可</li>
</ol>
</blockquote>
<h3 id="ⅷ-解决flex布局中-space-between方法的排版问题">Ⅷ-解决flex布局中 space-between方法的排版问题</h3>
<blockquote>
<p>flex布局 justify-content:space-between; 解决最后一排数量不够自动向两端排列问题</p>
<ol>
<li>问题图示:</li>
</ol>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203706662-243357571.png"></p>
<ol start="3">
<li>解决方法1:父级添加after伪类法<br>
<img src="https://img2022.cnblogs.com/blog/2498482/202202/2498482-20220216203807933-661951603.png"></li>
</ol>
<p>ps:这种解决方案只适合每列有<code>3个</code>的分布情况,如果布局每列有4个,5个,就需要解决方法2</p>
<ol start="4">
<li>解决方法2:使用grid栅格布局,此处不详解,只将解决方案指出,有需要的直接百度搜索<code>使用grid栅格布局</code>即可</li>
</ol>
</blockquote><br><br>
来源:https://www.cnblogs.com/mc-blog/p/15888448.html
頁: [1]
查看完整版本: 微信小程序开发基础篇