微信小程序之组件的集合(四)

  这个主要是来开发book的这个大模块的,看看如何优雅的开发出booked模块!

一、book模块的创建

这个就很简单了,创建一个大的框架是很简单的

技术图片

 二、组件的编写

(1)wxml组件页面的编码

首先是将一本书的展示看做是一个组件,然后就是循环展示所有请求的书籍的信息,所以需要把一本书当做一个组件来制作,这样就能比较合理的解决这个问题!

 1 // book组件的页面的代码 2 <view class="container"> 3 <image src="{{book.image}}"></image> 4 <view class="description"> 5 <text class="title">{{book.title}}</text> 6 <text class="author">{{book.author}}</text> 7 <view class="foot"> 8 <text class="footer">{{book.fav_nums}} 喜欢</text> 9 </view>10 </view>11 </view>

将这个book组件引用到page中去,给用户展示书籍的信息,需要在book.json 中引入,并且将组件的写到book.wxml页面代码中,这里暂时只是展示一个book组件

 1 // page中的book.json 中引入book组件 2 { 3  "usingComponents": { 4  "v-book":"/components/book/index" 5  } 6 } 7  8 // page中的book.wxml中引入v-book标签 9 <v-book book="{{books[0]}}" />10 11 // page中的book.js中操作数据,将数据传递到页面属性中,只写主要的生命周期函数12 import {13  BookModel14 } from ‘../../models/book.js‘;15 16 // 实例化BookModel对象17 const bookModel = new BookModel();18 19 Page({20 21  /**22  * 页面的初始数据23  */24  data: {25  // 服务器请求的数据 book的集合26  books:[]27  },28 29  /**30  * 生命周期函数--监听页面加载31  */32  onLoad: function(options) {33  // 这种写法才能规避回调地狱的34  bookModel.getHotList()35  .then(res => {36  // 这种写法不完善 只是做了赋值 页面无法获取到37  // this.data.books = res38  this.setData({39  books:res40  })41  })42 43 },

(2)book组件样式的编码

这个啊,让人头疼的,我是写不出来,哈哈

 1 .container{ 2  margin-top: 30rpx; 3  display: flex; 4  position: relative; 5  box-shadow: 2px 2px 3px #e3e3e3; 6  flex-direction: column; 7  width: 240rpx; 8  height: 360rpx; 9 }10 11 /* 书籍封面的样式 */12 .container image {13  width: 100%;14  height: 100%;15  border-radius: 2px;16 }17 18 .description{19  width: 216rpx;20  position: absolute;21  bottom: 0;22  background-color: #fff;23  padding: 5rpx 10rpx 8rpx 15rpx;24  font-size: 24rpx;25  display: flex;26  flex-direction: column;27  border-bottom-left-radius: 2px;28  border-bottom-right-radius: 2px;29 }30 31 .title{32  margin-top: 10rpx;33  text-overflow: ellipsis;34  white-space: nowrap;35  overflow: hidden;36 }37 38 .author{39  font-size: 20rpx;40  color: #999999;41  margin-bottom: 10rpx;42  text-overflow: ellipsis;43  white-space: nowrap;44  overflow: hidden;45 }46 47 .foot{48  font-size: 20rpx;49  display: flex;50  flex-direction: row;51  justify-content: flex-end;52 }53 54 .footer{55  color: 56 }

三、组件的应用

因为书籍是使用的一组的书籍组件,如何来把服务器上传回来的所有的书籍信息全部显示出来,这个就是我们需要考虑的,需要完成的

小程序中肯定是存在类似for循环的,那就是wx:for 但是在小程序中并不是叫做for循环,而是叫做列表渲染

(1)列表渲染

1 <block wx:for="{{books}}">2 <v-book book="{{item}}" />3 </block>

 (2)整体页面布局

这个就是pages中的book页面的代码了,主题包含一个搜索栏,以及下面的图书列表

 1 <view class="container"> 2 <view class="header"> 3 <view class="box"> 4 <image src="/images/icon/search.png"></image> 5 <text>搜索书籍</text> 6 </view> 7 </view> 8 <view class="sub-container"> 9 <image src="/images/book/quality.png" class="head-img"></image>10 <view class="books-container">11 <block wx:for="{{books}}">12 <v-book book="{{item}}" />13 </block>14 </view>15 </view>16 </view>

(3)整体的样式代码

看一下如何设计样式来让这个页面看起来那么舒服,这是最难的吧,充分灵活的使用flex布局来实现这样的样式

 1 .container{ 2  display: flex; 3  flex-direction: column; 4  align-items: center; 5  width:100%; 6 } 7  8  .sub-container{ 9  display: flex;10  flex-direction: column;11  align-items: center;12  background-color: #f5f5f5;13  margin-top:100rpx;14 /* z-index:0; */15 } 16 17 .books-container{18  margin-top:10rpx;19  display: flex;20  flex-direction: row;21  flex-wrap: wrap;22  padding: 0 90rpx 0 90rpx;23  justify-content: space-between;24 }25 26 .books-container v-book{27  margin-bottom: 30rpx;28 }29 30 .box{31  display:flex; 32  flex-direction: row;33  justify-content: center;34  align-items: center; 35  border-radius: 50px;36  background-color: #f5f5f5;37  height: 34px;38  width:700rpx;39  color:#999999;40 }41 42 .header{43 /* fixed 是使得容器固定 */44  position: fixed; 45  background-color: #ffffff;46  height:100rpx;47  width:100%;48  border-top:1px solid #f5f5f5;49  border-bottom:1px solid #f5f5f5;50  display: flex;51  flex-direction: row;52  align-items: center;53  justify-content: center;54  box-shadow:0 0 3px 0 #e3e3e3; 55  z-index: 99;56 }57 58 .head-img{59  width:106rpx;60  height:34rpx;61  margin-top:40rpx;62 }63 64 .box image{65  margin-right:10px;66  width:14px;67  height:14px;68  margin-bottom:-2px;69 }

四、book组件中业务逻辑的实现

这个主要是实现功能就是从book列表页面用户直接点击之后,跳转到书籍的详细信息的页面,这个该如何实现,是在组件中实现跳转逻辑,还是在页面上实现,如何取舍,如何选择,是选择组件的通用性呢?还是选择组件的设计实现简单呢?如何来写这个逻辑代码?

1、不考虑组件的通用性

不考虑组件通用性的话,就直接在组件中实现页面的跳转就OK了,具体的实现代码如下:

 1 // 组件中的wxml文件 2 <view bind:tap="onTap" class="container">  3 </view> 4  5 // 组件中的js文件 小程序中的navigateTo实现跳转 6  methods: { 7  onTap(event){ 8 const bid = this.properties.book.id; 9  wx.navigateTo({10 url: `/pages/book-detail/book-detail?bid=${bid}`,11  })12  }13 }

2、考虑组件通用性的

五、book详细信息的开发

1、小程序中的编译模式

为了方便开发,让小程序每次编译之后都会是书籍详细信息的页面,我们可以添加编译模式,来控制编译之后的启动页面,这样有利于提高开发效率:

技术图片

选择自己定义的编译模式:

技术图片

 2、具体book详情页面的开发

首先把详情页面的样式也页面的代码进行编写,这里就是没有按照顺序来整理出来代码,直接把完整的代码都拿出来吧

 首先是详情页面的wxml文件中静态页面代码:(这里不是完整的,下面的点评功能没有实现)

 1 <wxs src="../../util/filter.wxs" module="util"/> 2 <view class="container"> 3 <!-- 头部信息 --> 4 <view class="head"> 5 <image src="{{book.image}}"></image> 6 <text class="title">{{book.title}}</text> 7 <text class="author">{{book.author}}</text> 8 </view> 9 <!-- 短评 -->10 <view class="sub-container">11 <text class="headline">短评</text>12 <view class="comment-container">13 <block wx:for="{{util.limit(comments,10)}}" wx:key="">14 <v-tag tag-class="{{index==0?‘ex-tag1‘:‘‘ || index==1?‘ex-tag2‘:‘‘}}" text="{{item.content}}">15 <text class="num" slot="after">{{"+" + item.nums}}</text>16 </v-tag>17 </block>18 </view>19 <!-- 内容简介 -->20 <view class="sub-container">21 <text class="heading">内容简介</text>22 <text class="content" decode="{{true}}">{{util.format(book.summary)}}</text>23 </view>24 </view>25 <!-- 书籍出版信息 -->26 <view class="sub-container">27 <text class="heading">书籍信息</text>28 <view class="detail-container">29 <view class="vertical description">30 <text>出版社</text>31 <text>出版年</text>32 <text>页数</text>33 <text>定价</text>34 <text>装帧</text>35 </view>36 <view class="vertical">37 <text>{{book.publisher}}</text>38 <text>{{book.pubdate}}</text>39 <text>{{book.pages}}</text>40 <text>{{book.price}}</text>41 <text>{{book.binding}}</text>42 </view>43 </view>44 </view>45 </view>·

接下来是wxss样式的代码:

 1 .container { 2  background-color: #f5f5f5; 3  width: 100%; 4 } 5  6 .head { 7  background-color: #fff; 8  padding-top: 40rpx; 9  padding-bottom: 40rpx; 10  display: flex; 11  flex-direction: column; 12  align-items: center; 13 } 14  15 .title { 16  color: #2f2f2f; 17  margin-top: 20rpx; 18  font-size: 38rpx; 19  font-weight: 600; 20 } 21  22 .author { 23  font-size: 28rpx; 24  color: #999; 25 } 26  27 .head image { 28  width: 200rpx; 29  height: 300rpx; 30  box-shadow: 2px 2px 3px #e3e3e3; 31 } 32  33 .sub-container { 34  width: 690rpx; 35  display: flex; 36  flex-direction: column; 37  align-items: center; 38  margin-top: 30rpx; 39  background-color: #fff; 40  padding: 30rpx; 41 } 42  43 .headline { 44  font-size: 30rpx; 45  font-weight: 600; 46  color: #2f2f2f; 47  margin-bottom: 20rpx; 48 } 49  50 .comment-container { 51  display: flex; 52  flex-direction: row; 53  flex-wrap: wrap; 54 } 55  56 .comment-container v-tag { 57  margin-right: 15rpx; 58  margin-bottom: 10rpx; 59 } 60  61 .num { 62  margin-left: 10rpx; 63  font-size: 22rpx; 64  color: #aaa; 65 } 66  67 .content{ 68  text-indent: 58rpx; 69  font-weight: 500 70 } 71  72 /* 给标签前两个设置背景色 这种设置违背了组件的封装原则的*/ 73  74 /* 这里引入了小程序中的externalClasses来进行自定义组件的样式的设置 */ 75  76 /* .comment-container > v-tag:nth-child(1) > view{ 77  background-color: #fffbdd; 78 } 79  80 .comment-container > v-tag:nth-child(2) > view{ 81  background-color: #eefbff; 82 } */ 83  84 /* !important 强制提高外部样式的权限 */ 85  86 .ex-tag1 { 87  background-color: #fffbdd !important; 88 } 89  90 .ex-tag2 { 91  background-color: #eefbff !important; 92 } 93  94 /* 书籍出版信息样式 */ 95 .detail-container{ 96  width: 100%; 97  display: flex; 98  flex-direction: row; 99  justify-content: flex-start;100  margin-bottom: 100rpx;101  font-size: 28rpx;102  color: #666;103 }104 105 .vertical{106  display: flex;107  flex-direction: column;108 }109 110 .description{111  color: #999;112  margin-right: 30rpx;113 }

最后是book详情页面的js代码:

 1 import { 2  BookModel 3 } from ‘../../models/book.js‘; 4  5 // 实例化BookModel对象 6 const bookModel = new BookModel(); 7  8 Page({ 9 10 /**11  * 页面的初始数据12 */13  data: {14  comments:[],15 book:null,16 likeStatus:false,17 likeCount:018  },19 20 /**21  * 生命周期函数--监听页面加载22 */23 onLoad: function (options) {24 // 从外部页面传递过来的参数id25 const bid = options.bid;26  console.log(bid);27 const detail = bookModel.getDetail(bid);28 const comments = bookModel.getComments(bid);29 const likeStatus = bookModel.getLikeStatus(bid);30 31 // 利用promise的then的回调获取数据32 detail.then(res => {33 // console.log(res);34 this.setData({35  book:res36  })37  })38 39 comments.then(res => {40 // console.log(res);41 this.setData({42  comments:res.comments43  })44  })45 46 likeStatus.then(res =>{47 // console.log(res);48 this.setData({49  likeStatus:res.like_status,50  likeCount:res.fav_nums51  })52  })53 54 },

 3、小程序插槽slot

这里的插槽很适合来做自定义组件的,这种用法非诚灵活,感觉真的有一种美妙的感觉-slot的官方介绍:

https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#组件wxml的slot

其实文档中已经写的很清楚了,但是还是看一下老师的讲解,毕竟在实战中引用才是最重要的,如何将理论的东西应用到实战中,是很值得思考的东西

1 <view class="container">2 <slot name="before"></slot>3 <text>{{text}}</text>4 <!-- 微信小程序中的 插槽 slot -->5 <slot name="after"></slot>6 </view>

这个其实就相当于占位符,我事先在这里占有一个位置,随时等待有人来占有这个地方,但是如果没人来占,对总体的布局也不会产生影响,有人的话,我就要把这个人给你们展示出来了,这个人就和组件中的其他的标签融为一体了,注意这里需要指定slot的name值,因为在page中是需要根据name值来找具体哪个slot的

看page中如何插入到插槽中slot的:

1 <view class="sub-container">2 <text class="headline">短评</text>3 <view class="comment-container">4 <block wx:for="{{comments}}" wx:key="">5 <v-tag text="{{item.content}}">6 <text class="num" slot="after">{{"+" + item.nums}}</text>7 </v-tag>8 </block>9 </view>

这里是将text标签插入到插槽中,那么插槽中就会被一个text标签完全的占有了,你看到就是text标签中的内容了

但是,这样的话,slot并不会生效,需要在配置一个参数,就是:

1  options: {2 multipleSlots:true3 },

这样的话,才能实现slot的功能

4、小程序中的externalClasses

这个是说的是小程序中的自定义组件如何来引入外部样式类,就是如何将page中的样式放入到自定义组件中,使其生效,小程序提供了externalClasses这个配置,可以应用这个设置来解决这个问题

小程序中国的官方的介绍文档:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#外部样式类

还是来看一下这个东西是如何在实战中应用的:

首先,看自定义组件中需要设置哪些地方:

 1 // 首先是需要设置 js中配置 2  externalClasses:[ 3 ‘tag-class‘ 4  ], 5  6 // 其次是需要在页面中使用这个自定义class 7 <!-- tag标签组件 短评以及搜索中的标签组件 --> 8 <view class="container tag-class"> 9 <slot name="before"></slot>10 <text>{{text}}</text>11 <!-- 微信小程序中的 插槽 slot -->12 <slot name="after"></slot>13 </view>

这样的话,我们就可以在使用自定义标签的时候来传递样式进去了

 1 // 这里面有一个样式的切换 第一个和第二个分别展示不同的背景色  2 <view class="sub-container"> 3 <text class="headline">短评</text> 4 <view class="comment-container"> 5 <block wx:for="{{comments}}" wx:key=""> 6 <v-tag tag-class="{{index==0?‘ex-tag1‘:‘‘ || index==1?‘ex-tag2‘:‘‘}}" text="{{item.content}}"> 7 <text class="num" slot="after">{{"+" + item.nums}}</text> 8 </v-tag> 9 </block>10 </view>

再来看一下ex-tag1与ex-tag2的样式设置

1 .ex-tag1 {2  background-color: #fffbdd !important;3 }4 5 .ex-tag2 {6  background-color: #eefbff !important;7 }

注意:!important 这里是提高该样式的重要性的,如果没有的话,虽然外部样式已经设置进去了,但是可能会被默认的样式覆盖的,这里为了强制覆盖默认样式而进行的设置

 5、小程序中的wxs

这个文件的主要功能就是在wxml文件中可以调用外部的js代码,当然js代码是放在wxs文件中的,看看这个新的知识点是如何来实现的,官方文档:

https://developers.weixin.qq.com/miniprogram/dev/reference/wxs/01wxs-module.html

技术图片

 

 开始编写逻辑代码:

 1 // filter.wxs文件中代码 注意model.exports导出 var关键字 正则替换写法 2 var format = function(text){ 3 if(!text){ 4 return 5  } 6 var reg = getRegExp(‘\\\\n‘,‘g‘); 7 return text.replace(reg,‘\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘); 8  9 }10 11 module.exports = {12  format:format13 }14 15 // 页面中的引入代码16 <wxs src="../../util/filter.wxs" module="util"/>17 // 标签中使用18 <text class="content" decode="{{true}}">{{util.format(book.summary)}}</text>

 

相关文章