笔记内容:编写第二个页面:新闻阅读列表页面
笔记日期:2018-01-06


使用Swiper组件构建轮播图

关于Swiper组件的官方描述文档:
https://mp.weixin.qq.com/debug/wxadoc/dev/component/swiper.html

示例:
post.wxml文件:

<view> <!-- 需要在父节点里定义宽高,indicator-dots属性指定显示轮播图的小点,纵向滚动则使用vertical属性 --> <swiper indicator-dots='true' autoplay='true' interval='2000' > <!-- 每一项里都放了一个图片 --> <swiper-item> <image src='/images/wx.png'></image> </swiper-item> <swiper-item> <image src='/images/vr.png'></image> </swiper-item> <swiper-item> <image src='/images/iqiyi.png'></image> </swiper-item> </swiper></view>

post.wxss文件:

swiper{ width:100%; height:500rpx}swiper image{ width:100%; height:500rpx}

运行结果:

构建新闻列表

json配置文件的官方参考文档:
https://mp.weixin.qq.com/debug/wxadoc/dev/framework/config.html

注:除了app.json之外的json文件都只能配置window属性,由于只能配置window属性所以就不需要显式标明了,直接设置window中的属性+值即可。

构建一个简单的新闻列表示例:
post.wxml文件:

<view> <!-- 需要在父节点里定义宽高,indicator-dots属性指定显示轮播图的小点,纵向滚动则使用vertical属性 --> <swiper indicator-dots='true' autoplay='true' interval='5000'> <!-- 每一项里都放了一个图片 --> <swiper-item> <!-- 使用绝对对路径 --> <image src='/images/wx.png'></image> </swiper-item> <swiper-item> <image src='/images/vr.png'></image> </swiper-item> <swiper-item> <image src='/images/iqiyi.png'></image> </swiper-item> </swiper> <view class='post-container'> <view class='post-author-date'> <image src='/images/avatar/1.png' class='post-author'></image> <text class="post-date">Jan 06 2018</text> </view> <text class='post-title'>正是虾肥蟹壮时</text> <image class='post-image' src='/images/post/crab.png'></image> <text class='post-content'> “山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。 </text> <view class='post-like'> <!-- 使用相对路径 --> <image src='../../images/icon/chat.png' class='post-like-img' ></image> <text class='post-like-font'>92</text> <image src='../../images/icon/view.png' class='post-like-img' ></image> <text class='post-like-font' >65</text> </view> </view> <view class='post-container'> <view class='post-author-date'> <image src='/images/avatar/2.png' class='post-author'></image> <text class="post-date">Jan 03 2018</text> </view> <text class='post-title'>比利·林恩的中场战事</text> <image class='post-image' src='/images/post/bl.png'></image> <text class='post-content'> 伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。 </text> <view class='post-like'> <!-- 使用相对路径 --> <image src='../../images/icon/chat.png' class='post-like-img' ></image> <text class='post-like-font'>92</text> <image src='../../images/icon/view.png' class='post-like-img' ></image> <text class='post-like-font' >65</text> </view> </view></view>

post.wxss文件:

swiper{ width:100%; height:600rpx}swiper image{ width:100%; height:600rpx}.post-container{ display: flex; flex-direction: column; margin-top:20rpx; margin-bottom: 40rpx; background-color: #fff; border-bottom: 1px solid #ededed; border-top: 1px solid #ededed; padding-bottom: 5px;}.post-author-date{ margin: 10rpx 0px 20rpx 10rpx ;}.post-author{ width: 30px; height: 60rpx; vertical-align: middle;}.post-date{ margin-left: 20rpx; vertical-align: middle; margin-bottom: 5px; font-size: 26rpx;}.post-title{ font-size: 34rpx; font-weight: 600; color: #333; margin-bottom: 10px; margin-left: 10px;}.post-image{ margin-left: 16px; width: 100%; height: 340rpx; margin: auto 0;}.post-content{ color: #666; font-size: 28rpx; margin-bottom: 20rpx; margin-left: 20rpx; letter-spacing: 2rpx; line-height: 40rpx;}.post-like{ font-size: 13px; flex-direction: row; line-height: 16px; margin-left: 10px;}.post-like-img{ height: 16px; width: 16px; margin-right: 8px; vertical-align: middle;}.post-like-font{ vertical-align: middle; margin-right: 20px;}

post.json文件:

{ "navigationBarBackgroundColor": "#405f80", "navigationBarTitleText": "文与字"}

运行结果:

js文件结构与Page页面的生命周期

小程序中的js文件结构与我们平时在web前端开发中的js文件有些差别,在小程序中需要把变量、函数等代码写到Page( )里。有点像json注册信息一样,在格式上也有点像,以下是小程序工具自动生成的js文件代码:

Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { console.log("onload") }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady: function () { console.log("onready") }, /** * 生命周期函数--监听页面显示 */ onShow: function () { console.log("onshow") }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () { console.log("onHide") }, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { console.log("onUnload") }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { }})

从以上生成的代码可以看到,所有的函数都写在Page里,而且如果js文件中没有这个Page就会报错,所以即便不写代码也要写个空Page在那。

官方给出的关于page页面生命周期的文档:
https://mp.weixin.qq.com/debug/wxadoc/dev/framework/app-service/page.html

数据绑定

在实际开发中,我们的数据都是需要临时从服务器上download下来的,例如在web开发中我们都是通过JavaScript脚本代码去请求服务器,得到服务器返回的数据然后将其在页面上显示出来,在小程序中也是如此。

在小程序中获取脚本文件的数据是通过数据绑定的机制来获取的,不需要像web中那样通过getElementById函数来获得元素对象,然后再设置到元素上,例如:

data: { date:"Jan 06 2018" title:"正是虾肥蟹壮时" },

然后在wxml中通过两个大括号就可以获得值了:

<text class="post-date">{{date}}</text><text class='post-title'>{{title}}</text>

注:在小程序中,这种数据绑定是单向的。

现在我们就可以把数据都转移到js文件中,然后通过数据绑定机制来在xwml中获得数据:
post.js代码:

// 写在这个函数内是为了在页面加载时就加载数据 onLoad: function (options) { var post_content1={ date:"Jan 06 2018", title:"正是虾肥蟹壮时", post_img:"/images/post/crab.png", content:"“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。", view_num:"112", collect_num:"96", author_img:"/images/avatar/1.png" } // 调用这个方法就相当于把数据都写在data里了 this.setData(post_content1); },

post.wxml代码:

<view class='post-container'> <view class='post-author-date'> <image src='{{author_img}}' class='post-author'></image> <text class="post-date">{{date}}</text> </view> <text class='post-title'>{{title}}</text> <image class='post-image' src='{{post_img}}'></image> <text class='post-content'>{{content}}</text> <view class='post-like'> <!-- 使用相对路径 --> <image src='../../images/icon/chat.png' class='post-like-img' ></image> <text class='post-like-font'>{{view_num}}</text> <image src='../../images/icon/view.png' class='post-like-img' ></image> <text class='post-like-font' >{{collect_num}}</text> </view> </view>

从以上两个对应的代码片段可以看到,数据绑定机制的方便之处。

注意:我们都知道在一些标签的属性上需要提供布尔类型的值,例如,之前提到过swiper的vertical属性,但是有时候会遇到明明给的值是false,却依旧还是垂直滚动,这是因为给的并不是布尔值,而是一个false字符串,在小程序中只要字符串不为空都会被认为是true,解决这种问题就需要使用数据绑定的语法来设定值:

<!-- 这种方式给的是字符串 --><swiper vertical="false"><!-- 这种方式给的才是布尔值 --><swiper vertical="{{false}}">

关于嵌套数据的拿值方式:
在设置数据属性的时候可以把一组同类的数据都设置在一个数据里形成一个数组形式,例如我把设置照片路径数据的属性都统一写在img属性里:

img:{ post_img: "/images/post/crab.png", author_img: "/images/avatar/1.png" },

拿值的时候通过访问符 . 来访问就可以了, 例如:父属性.子属性 就可以了:

<image src='{{img.author_img}}' class='post-author'></image><image class='post-image' src='{{img.post_img}}'></image>

控制一个标签显示/隐藏的语法:
小程序里有一个语法可以控制标签的显示或隐藏:

<!-- false: 隐藏,true: 显示 --><image wx:if="{{false}}" src='{{img.author_img}}' class='post-author'></image>

使用数据绑定机制:

<!-- js代码 -->img_condition:true,<!-- wxml代码 --><image wx:if="{{img_condition}}" src='{{img.author_img}}' class='post-author'></image>

运算:
在两个大括号中可以进行一些简单的运算,例如:数值型的数据可以进行算术运算,字符串则可以进行字符串连接运算等。

简单的加法运算示例:

<!-- js代码 -->a:1,b:2,c:3<!-- wxml代码 --><text class="post-date">{{a+b+c}}</text>

以下是官方的参考文档:

https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/data.html

使用wx-for来改写新闻列表

以上我们虽然通过数据绑定解决了动态加载服务器数据的问题,但是还有一个问题就是组件代码重复太多,因为上线使用后不可能只有两篇文章,会有很多篇文章。如果每一篇文章都得重复的去拷贝相同的代码就有点麻烦了,所以我们还需要解决这个代码重复的问题——使用for循环:

1.首先将js文件中的数据整合成一个数组:

onLoad: function (options) { // 将数据整合成数组类型 var posts_content = [ { date: "Jan 06 2018", title: "正是虾肥蟹壮时", post_img: "/images/post/crab.png", author_img: "/images/avatar/1.png", content: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。", view_num: "112", collect_num: "96", }, { date: "Jan 03 2018", title: "比利·林恩的中场战事", post_img: "/images/post/bl.png", author_img: "/images/avatar/2.png", content: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。", view_num: "92", collect_num: "65", } ] // 因为是数组,所以需要使用这种方式将数据填充到data里 this.setData({ posts_key: posts_content }); },

2.使用for循环来进行数据绑定:

<view> <!-- 需要在父节点里定义宽高,indicator-dots属性指定显示轮播图的小点,纵向滚动则使用vertical属性 --> <swiper indicator-dots='true' autoplay='true' interval='5000'> <!-- 每一项里都放了一个图片 --> <swiper-item> <!-- 使用绝对对路径 --> <image src='/images/wx.png'></image> </swiper-item> <swiper-item> <image src='/images/vr.png'></image> </swiper-item> <swiper-item> <image src='/images/iqiyi.png'></image> </swiper-item> </swiper> <!-- wx:for需要接收一个数组、集合类型的值,wx:for-item用于设置一个变量来代表子元素 --> <!-- wx:for-index用于设置一个变量来代表下标值 --> <block wx:for="{{posts_key}}" wx:for-item="item" wx:for-index="index" > <view class='post-container'> <view class='post-author-date'> <image src='{{item.author_img}}' class='post-author'></image> <text class="post-date">{{item.date}}</text> </view> <text class='post-title'>{{item.title}}</text> <image class='post-image' src='{{item.post_img}}'></image> <text class='post-content'>{{item.content}}</text> <view class='post-like'> <!-- 使用相对路径 --> <image src='../../images/icon/chat.png' class='post-like-img'></image> <text class='post-like-font'>{{item.view_num}}</text> <image src='../../images/icon/view.png' class='post-like-img'></image> <text class='post-like-font'>{{item.collect_num}}</text> </view> </view> </block></view>

注:wx:for-item和wx:for-index不设置也可以,因为默认值就是item和index,直接用就可以了。

可以看到以上示例使用循环后就减少了很多重复性的代码。

小程序的事件机制(冒泡与非冒泡)

到目前为止,我们就编写好了两个页面——启动页面和新闻列表页面,现在我们需要通过小程序的事件机制,让我们点击启动页面的时候,就能够进入到新闻列表页面。

以下是官方给出的事件使用文档:

https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/event.html

我们需要用到的事件是 tap ,这个事件相当于html中的click事件。小程序中有个规定,需要在事件名称前加上bind或者catch。例如我要使用tap事件,那么就需要在前面加上bind或者catch,结合起来就是bindtap或catchtap。

示例:

welcome.wxml文件代码:

<!-- wxml是编写小程序骨架的文件 --><!-- view和html中的div是一样的 --><view class="container"> <!-- 无需导入wxss文件 --> <image class="user-avatar" src="/images/image.png"></image> <text class="user-name">Hello Wolrd!</text> <!-- 注册tap事件,值对应的是函数名称 --> <view class="moto-container" bindtap='onTap' > <text class="moto">开启小程序之旅</text> </view></view>

welcome.js文件代码:

// 所有代码都需要写在Page里Page({ onTap:function(){ // 通过wx.redirectTo方法来实现页面跳转 wx.redirectTo({ // 不需要指明后缀名,小程序会自动识别 url: "../posts/post", }) }})

编写完以上代码后,就可以点击启动页中的view组件跳转到新闻列表页面了。

redirectTo方法是重定向方式的跳转,这种方式的跳转是完全跳转到另一个页面中,由于重定向跳转会卸载掉当前页面,这个过程会触发Page生命周期中的Unload事件。示例:

Page({ onTap:function(){ wx.redirectTo({ url: "../posts/post", }) }, onUnload:function(){ console.log("unloading this page"); }})

运行结果:

从运行结果可以看到,没有返回上一级页面的按钮

控制台打印结果:

unloading this page

另一种跳转方式是使用navigateTo方法进行跳转,这个方法只会导航到另一个页面,当前页面只是隐藏掉,所以跳转之后还可以返回上一级页面,同样的这个过程也会触发相应的事件,这个事件就是onHide事件。示例:

Page({ onTap:function(){ // 与redirectTo方法的使用方式基本是一样的 wx.navigateTo({ url: "../posts/post", }); }, onHide:function(){ console.log("hideing this page"); }})

运行结果:

控制台打印结果:

hideing this page

以上演示的navigateTo方法只是部分结构,完整的结构如下:

Page({ onTap:function(){ wx:wx.navigateTo({ url: '../posts/post', success: function(res) { // 跳转成功后的回调函数 }, fail: function (res) { // 跳转失败后的回调函数 }, complete: function (res) { // 无论跳转成功或失败都会回调的函数 }, }) },})

注:redirectTo方法也是一样的,完整结构也是会有三个回调函数。

冒泡事件与非冒泡事件的区别:

冒泡事件就是当父节点和子节点都有监听事件时,触发子节点的事件也会一并触发父节点的事件。但是触发父节点的事件并不会触发子节点的事件,这种机制就是冒泡事件,示例:

wxml代码:

<view class="moto-container" bindtap='onContainerTap' > <text class="moto" bindtap='onSubTap'>开启小程序之旅</text></view>

js代码:

Page({ onContainerTap:function(){ console.log("excute onContainerTap"); }, onSubTap:function(){ console.log("excute onSubTap"); }})

触发子节点的事件后控制台的打印结果:

excute onSubTap
excute onContainerTap

触发父节点的事件后控制台的打印结果:

excute onContainerTap

非冒泡事件则是反之,触发子节点的事件并不会触发父节点的事件。

在小程序中,我们可以阻止事件的冒泡,让原本有冒泡性质的事件指定为非冒泡性质,方法也很简单,就是把bind改为catch即可,示例:

<view class="moto-container" catchtap='onContainerTap' > <text class="moto" catchtap='onSubTap'>开启小程序之旅</text></view>

js代码不变,触发子节点的事件后控制台的打印结果:

excute onSubTap

触发父节点的事件后控制台的打印结果:

excute onContainerTap

注:在小程序中,绝大多数的事件都是冒泡事件。

至于哪些事件是冒泡事件,哪些事件是非冒泡事件,可以参照以下的官方说明文档:

https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/event.html