原生框架开发入门(二) —— 博客首页文章列表实现(上)


接下来,我们将结合具体项目实例来介绍如何通过原生框架来构建微信小程序版的博客应用

页面功能设计

我们在上一篇教程中已经介绍过小程序的目录结构,了解了目录结构基本上也就了解了实现什么功能要怎么编写代码。以博客首页为例,需要先构思如何渲染首页页面,构思清楚之后,就可以打开根目录下的 app.json 配置文件,在 pages 配置项中新增首页目录路径:

"pages":[
    "pages/index/index",
    "pages/logs/logs"
],

首页目录路径已经存在了,并且小程序默认 pages 配置的第一个页面渲染的就是项目首页。然后,我们将该配置文件 window 配置项的 navigationBarTitleText 配置值修改为你的应用名称,比如这里将其改成「Laravel学院」,这样重新编译项目,就会在小程序顶部将项目名称改成「Laravel学院」了:

-w320

接下来,就可以到 pages/index 目录下修改首页 WXML、WXSS、JS 等文件代码,实现对应的效果和功能了。

首页 WXML

首先,我们来编写首页 index.wxml 文件代码,我们前面提到过 WXML 相当于 HTML,只不过有一些自己提供的特殊语法和组件,关于 WXML 的技术细节,请参考小程序官方文档,这里我们直接演示如何编写 WXML 代码。

原生框架提供了丰富的内置组件帮助我们快速像搭积木一样完成页面结构搭建,此外,我们还可以自定义组件来实现更加复杂或者个性化的需求。

注:如果你之前使用过 Vue.js 的组件功能,可以很快入门小程序的组件功能。

我们在博客首页中就会基于组件来实现轮播图和首页文章列表的渲染。

自定义卡片组件

初始化目录结构

在重构项目首页 WXML 代码之前,先创建一个自定义的卡片组件用于渲染文章列表显示项。在 pages 目录下创建一个子目录 components 用于存放所有自定义组件代码,然后在 components 子目录下创建一个 card 子目录用于存放卡片组件相关代码,在微信开发者工具中,选中 card 子目录,右键点击「新建 Component」,即可快速初始化卡片组件相关文件:

-w286

和页面一样,组件也包含 js、json、wxml、wxss 格式文件,含义也一样,不再过多描述。

编写card.wxml文件

我们在 card.wxml 中编写组件 WXML 代码如下:

<view class="card">
    <text class="title">{{title}}</text>
    <view class="content-area">
        <view class="left-area">
            <text class="card-content">{{content}}</text>
            <view class="info-area">
                <text class="posted-date">{{date}}</text>
                <text class="views">{{views}}</text>
            </view>
        </view>
        <view class="right-area">
            <image src='{{thumbnail}}' class="thumbnail" mode="aspectFill"/>
        </view>
    </view>
</view>

我们在 WXML 通过动态绑定渲染视图数据,接下来需要在 card.js 文件中定义这些变量。

编写card.js文件

我们在 card.js 文件中通过定义 properties 属性从外部引入上述视图中的变量:

// pages/components/card/card.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    title: String,
    content: String,
    date: String,
    views: Number,
    thumbnail: String
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})

data 属性和 methods 属性留空。

编写card.wxss文件

最后我们来编写用于定于组件样式的 card.wxss 文件,WXSS 和 CSS 类似,只不过支持一些额外的语法,具体可参考官方文档,我们通过 card.wxss 编写样式代码如下:

@font-face {
  font-family: "iconfont";
  src: url('iconfont.eot?t=1545317804991');
  /* IE9*/
  src: url('iconfont.eot?t=1545317804991#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAhAAAsAAAAADCwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8f1DDY21hcAAAAYAAAAB1AAAByIl8nPJnbHlmAAAB+AAABC8AAAWk6fMuMmhlYWQAAAYoAAAALwAAADYTouFVaGhlYQAABlgAAAAcAAAAJAfeA4dobXR4AAAGdAAAAA4AAAAYGAAAAGxvY2EAAAaEAAAADgAAAA4F+AQAbWF4cAAABpQAAAAfAAAAIAEeANVuYW1lAAAGtAAAAUUAAAJtPlT+fXBvc3QAAAf8AAAAQgAAAFRi1hifeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByecb67yNzwv4EhhrmBoQEozAiSAwDuBQzFeJztkcsNhDAMRF8gQbsrSqEShCiDEjhtAbRHEz7SAvgDSPTARC/STOwcbKAAtdIpGdKfhGnWNHle8/M806tv+VCR5SujTLJs677D091KWn0d/L9ivfrQ8Kr1ezhdsSkGtg8ZA9uBTIHXLIHOkW0NyAe0RyF6AAAAeJx1VEFvG0UUfm/G3o3teOON1157HbveXcWbNM6Geu11kpYktkilOEljB1DU4ohLS3JolFChJGoU5BYqogioEAcC5cAFqZw5cEBquMEBWh/4AUiceigXpAokumV2XTflwO7ozfe+mTf7Ps17CwLA0xZ9TFsQAhnyMAFzsAirsAH78BEcwV34Fn4C8JtoTGE5g7KAVECeAeaaGB3DnJF7GYt22cpgGuUMsg0mjmCJ+bKYG0NdyxmlKTyLhbgcE3BQjak849wYl0ujxPExiRvBE47XTTw5U+Lk/y7HyhbXPYKWiraldo7RVS0nP4tUOR5FKS6rbLDcRZatFdM1jjy8dkTp0bWObe4RstdcvU7p9cj7PT6CQpCEhK1gDy/WMR23rPwkJpXPSVBAd8mbnNtoOb9YzPE2C71CkLqYmUQXCMIJufBZ0H/gUuEQvudyzn4onHABSlrKeSUdx9fCUefD/ATiRN6y4umWlx8hrsXfuwmuNvecdpHz8ZTe7OTzdt7XLwXIl/G0hZMjzp88fSiE7rCUXNOyFk+co+eJHWM4REJh7Ew3u3QwkVQ8OXii4e4zyfEMrj15K5bGVIJ9hnwxMolWGtjDs9r5nn5CZ0GEDJyCUTChAlUA1ExSnCKFDJEEoosv1ItxBnN22bZiGs/xAsq8ashGwTZy7quXCqx++DMERhsz2exM443OZNYuE3K5Nu/aeecdHz9+5dF2vZob81OTJk1ZRkJ7ho1KffvRlXHeh1Wj1lxbrRlGbXWtWTPwV7J78dIOITuXLu6Sf77uubWwa2aT5symLxDw+zVltmAqp8zdhVs9ABzT9CN9SsteP+gwDXVoAERN7NQZK1Z8EWu5Ltaj2hgyVUxkrliecss9Q7g+lNkaahzPSUxcgYkvGibqyUA4HMCia52fPfySh9uupfc9Jsgd4HTDXFarVXW5+Wo2o/mSCh5wYef+YFUplZRqrarYtlIdxHnsjYbD0V7EuS56YoVdEMZF/gAtRC17/rvzWV3PZhZfX1LxgGdLjweU8U/HlVTKmwbYnfrdi6X75DeIgwFn4RzMAgxqrI9d1WVkDcjuMibxrM+NeIERrN0MXeOR6fNrJtodyvZakrFRXYoz1SZy+K48HLkdEcUIVqRUeyCHkvND5PS5yAgjCN+mhLkRnAv08T6OMaIisg2BZS2ajiKq2jkx8nHk9OiwiDMS5tIPBtxwcb6vj+2lD3gkznEk3/d3UOx3o2m7VxR72ynJOQ6QfiEaFaKSBODz9H1FvoEYqKxibVatJtUEwi4qQwtTZBr/71/Hm54siaN35MbmjcPWVj3h8yXqW63DG5sN2ee8uX3PNO9t77h2p7JCyEqluoK4Uh0qlxu2jYfT6xeGhy+sTweD0+tLQ0NLDP2BrY2rLUJaVzda+MHziMrKX2gv22wA/AvmHPSCAHicY2BkYGAA4idPkuLi+W2+MnCzMIDADcdzaxD0/wYWBuYGIJeDgQkkCgBQ2AtvAHicY2BkYGBu+N/AEMPCAAJAkpEBFbABAEcMAm94nGNhYGBgwYIBAWgAGQAAAAAAAAEeAYgCCAJ4AtIAAHicY2BkYGBgYzjJwMcAAkxAzAWEDAz/wXwGAB3PAfQAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicbcFBCoAwDATAbK1R/GWEiAshpUIvfb0Hr85Ikc8h/xQFCypWKDapDzt1jjZv18sznPtJa52WGhxhKfICAnMM6AAA') format('woff'), url('iconfont.ttf?t=1545317804991') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ url('iconfont.svg?t=1545317804991#iconfont') format('svg');
  /* iOS 4.1- */
  font-weight: normal;
  font-style: normal;
}
.card {
  -webkit-font-smoothing: antialiased;
  background-color: #fff;
  padding: 25rpx 25rpx;
  margin-bottom: 30rpx;
  overflow: hidden;
  color: #333;
}
.card .title {
  font-size: 18px;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.card .content-area {
  display: -webkit-box;
}
.card .content-area .left-area {
  -webkit-box-orient: vertical;
  -webkit-box-flex: 1;
}
.card .content-area .left-area .card-content {
  line-height: 1.3;
  font-size: 14px;
  margin: 10rpx 0;
  font-family: HelveticaNeue-Light;
  overflow: hidden;
  color: #666;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}
.card .content-area .left-area .info-area {
  font-size: 10pt;
  color: #666;
  opacity: 0.8;
  font-family: 'iconfont';
}

.card .content-area .left-area .info-area .posted-date:before {
  content: '\e64e';
  margin-right: 10rpx;
}
.card .content-area .left-area .info-area .views {
  margin-left: 30rpx;
}
.card .content-area .left-area .info-area .views:before {
  content: '\e666';
  margin-right: 10rpx;
}
.card .content-area .right-area {
  margin-left: 20rpx;
}
.card .content-area .thumbnail {
  width: 150rpx;
  height: 150rpx;
  background-color: #eee;
  margin-top: 26rpx;
}

注意到我们在样式代码中使用了 @font-face,其用处是通过 CSS 实现小程序中使用的 icon 图标(iconfont),这里我是通过阿里巴巴矢量图标库下载的代码来实现,我在项目使用了是以下图标:

登录后选择下载代码即可下载对应的资源,解压下载包,打开 iconfont.css,将上述 WXSS 文件中的链接和图标名称替换成自己的即可。

card.json 暂时保持不变。至此,我们就完成了卡片组件的编写,接下来,我们需要到博客首页使用这个组件。

在页面中使用组件

我们将在小程序首页显示最新文章列表,因此需要在 pages/index/index.json 中引入刚刚创建的卡片组件,以便通过它来渲染文章列表:

{
  "usingComponents": {
    "card": "/pages/components/card/card"
  }
}

这样我们就可以在首页视图中通过 card 组件来渲染列表文章项了。

初始化index.js文件

然后在 pages/index/index.js 中定义文章模型数据以便在视图中渲染:

Page({
  ...
  data: {
    articles: [
      {
        'id': 1,
        'title': '测试文章标题1',
        'summary': '测试文章内容',
        'posted_at': '2018-09-01',
        'views': 100,
        'thumb': 'https://xueyuanjun.com/wp-content/uploads/2018/12/09cf86cb5ac710f09c8fe05892e521b1-150x150.jpg' 
      },
      {
        'id': 2,
        'title': '测试文章标题2',
        'summary': '测试文章内容',
        'posted_at': '2018-09-01',
        'views': 100,
        'thumb': 'https://xueyuanjun.com/wp-content/uploads/2018/12/09cf86cb5ac710f09c8fe05892e521b1-150x150.jpg'
      },
      {
        'id': 3,
        'title': '测试文章标题3',
        'summary': '测试文章内容',
        'posted_at': '2018-09-01',
        'views': 100,
        'thumb': 'https://xueyuanjun.com/wp-content/uploads/2018/12/09cf86cb5ac710f09c8fe05892e521b1-150x150.jpg'
      },
      {
        'id': 4,
        'title': '测试文章标题4',
        'summary': '测试文章内容',
        'posted_at': '2018-09-01',
        'views': 100,
        'thumb': 'https://xueyuanjun.com/wp-content/uploads/2018/12/09cf86cb5ac710f09c8fe05892e521b1-150x150.jpg'
      },
      {
        'id': 5,
        'title': '测试文章标题5',
        'summary': '测试文章内容',
        'posted_at': '2018-09-01',
        'views': 100,
        'thumb': 'https://xueyuanjun.com/wp-content/uploads/2018/12/09cf86cb5ac710f09c8fe05892e521b1-150x150.jpg'
      },
    ],
    isLoadingMore: false,
    currentPage: 1,
    info: ''
  },
  ...

文章模型数据 articles 用于渲染文章列表,现在填充的是测试数据,后续会通过博客后台 API 获取,isLoadingMore 用于标识是否还能加载更多,currentPage 用于表示当前页码,info 用于提示文章加载中及没有更多文章。

编写 index.wxml 代码

接下来我们来编写 pages/index/index.wxml 中的视图逻辑:

<!--index.wxml-->
<view class="container">
  <view class="cards-area">
        <view wx:for="{{articles}}">
            <view bindtap="tap('{{item.id}}')" wx:if="{{item.id}}">
              <card title="{{item.title}}" content="{{item.summary}}" date="{{item.posted_at}}" views="{{item.views}}" thumbnail="{{item.thumb}}"/>
            </view>
        </view>
    </view>
    <text class="info" wx:if="{{info}}">{{info}}</text>
</view>

index.wxml 中,我们通过列表渲染来显示文章列表,并且通过 card 组件渲染列表文章项。

首页 WXSS

我们在自定义卡片组件时已经介绍过 WXSS 了,接下来,我们来编写首页样式代码,打开 pages/index/index.wxss,编写代码如下:

/**index.wxss**/
.container {
  background-color: #eee; 
  padding: 30rpx 0;
}

.cards-area {
  width: 100%; 
}

.cards-area .date {
    color: #666;
    text-align: center;
    margin-bottom: 10rpx;
    opacity: .8; 
}

.cards-area .date:before {
    position: absolute;
    content: "————";
    left: 450rpx;
    right: 0; 
}
.cards-area .date:after {
    position: absolute;
    content: "————";
    left: 0;
    right: 450rpx; 
}

.info {
  color: gray;
  opacity: .8;
  margin-bottom: 20rpx; 
}

.info.loading {
    width: 70rpx;
    height: 70rpx; 
}

在微信开发者工具中,每次修改文件后小程序会自动重新编译,此时,我们已经可以在左侧看到文章列表渲染效果了:

-w344

在下一篇教程中,我们将介绍如何通过 js 代码从后台 API 接口获取博客文章数据来渲染列表,并实现上推翻页,下拉刷新功能。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 原生框架开发入门(一) —— 项目初始化和目录结构

>> 下一篇: 原生框架开发入门(三) —— 博客首页文章列表实现(下)