微信小程序实用指南2:模仿知乎
1开始之前
除了小程序项目自带的文件夹外,我还引入了几个新文件夹:
- .vscode文件夹,用于存放vscode编辑器服务器配置文件。
- Component 文件夹存储组件。
- 图片文件夹存放公共图片。
- Mock文件夹存放的是使用MockJS模拟后端接口的类。
- models文件夹存放封装好的请求类。
- utils文件夹存放公共类。
那我就以首页为例进行分析,其他页面类似。
建议能力强的朋友先下载项目,按照效果图尝试实现代码。完成后,回来看看它与我的想法有何不同。
2 入门
2.1 布局和风格
此页面上的每个条目都是相同的,因此可以将其抽象为组件并在组件文件夹下创建组件。 wxml和wxss比较简单,不提供太多解释。
//wxml
<view class="container-item">
<view class="item-title">
<text>{{items.title}}</text>
<image ></image>
</view>
<view class="item-author">
<image ></image>
<text>{{items.author}}</text>
</view>
<text class="text-body">{{items.content}}</text>
<view class="item-action">
<text>{{items.starNum}}</text>
<text>赞同</text>
<text>{{items.reviewNum}}</text>
<text>评论</text>
</view>
</view>
//部分scss
$border-color:#dfdfdf;
.container-item {
padding:10rpx;
display: flex;
flex-direction: column;
width: 100%;
background-color: #fff;
margin-top: 10rpx;
border-top: 1px solid $border-color;
border-bottom: 1px solid $border-color;
}
复制代码
2.2 子组件和父组件的粒度
子组件必须监听两个事件,触摸子组件时应该跳转到问题答案的详情页,按下子组件中的三个点时跳转右上角,进入问题详情页面。当第二个事件触发时,它会冒泡并触发第一个事件,因此当您监听第二个事件时,请使用 catch 前缀来监听并防止事件冒泡。完整代码如下。
<view class="container-item" bind:tap="clickItems">
<view class="item-title">
<text>{{items.title}}</text>
<image catch:tap="clickMore"></image>
</view>
<view class="item-author">
<image ></image>
<text>{{items.author}}</text>
</view>
<text class="text-body">{{items.content}}</text>
<view class="item-action">
<text>{{items.starNum}}</text>
<text>赞同</text>
<text>{{items.reviewNum}}</text>
<text>评论</text>
</view>
</view>
复制代码
抽象子组件并不难。难的是如何设计子组件和父组件的粒度。在上面的示例中,子组件侦听触摸事件。此时,子组件是在运行wx.navigateTe()还是父组件的执行是我们最需要考虑的。我的想法是子组件只控制样式变化,不执行业务逻辑。我将业务逻辑留给父组件。
以下代码参考微信小程序实战指南 - 1 基础知识5.2.2
//子组件中将index传给父组件,让父组件执行业务逻辑
methods: {
//打开回答详情
clickItems() {
let index=this.properties.index;
this.triggerEvent('clickItems',{index});
},
//打开问题详情
clickMore() {
let index=this.properties.index;
this.triggerEvent('clickMore',{index});
}
}
//父组件中监听子组件准备触发的事件并执行业务逻辑
//wxml
<view class="container">
<block wx:for="{{items}}" wx:for-item="v" wx:for-index="i">
<index-items items="{{v}}" index="{{i}}" bind:clickItems="clickItems" bind:clickMore="clickMore"></index-items>
</block>
</view>
//js
//点击回答打开详情
clickItems(event) {
//取出子组件传来的index,表示被点击的子组件的下标
let index=event.detail.index;
let id=this.data.items[index].id;
wx.navigateTo({
url: '/pages/detail/detail?id='+id
});
},
//点击打开问题详情
clickMore(event) {
let index=event.detail.index;
let id=this.data.items[index].id;
wx.navigateTo({
url:"/pages/problem/problem?id="+id
});
}
复制代码
2.3 使用Mock创建虚拟数据
首页分析发现每个帖子都需要标题、作者ID、 、作者姓名、文字内容、点赞数和回复数。
在Mock文件夹下创建一个indexMock.js文件,专门为首页提供虚拟数据。
//indexMock.js
let Mock = require('./mock-min.js');//引入Mock
const Random = Mock.Random;
class IndexMock {
constructor() {}
//返回首页记录模拟数据
getIndexList() {
return Mock.mock({
'status': '0',
'msg': '',
'data|10': [{
'id': '@guid()', //id
'img': Random.img('16x16', '#4A7BF7','#000','@word(1,2)'), //头像
'title': '@ctitle(1,8)', //标题
'author':'@word(1,8)', //作者
'content':'@cparagraph(1)', //正文
'star_num': '@integer(0,10000)', //点赞数量
'review_num':'@integer(0,1000)' //回复数量
}]
});
}
}
export { IndexMock };
复制代码
2.4 封装AJAX请求
微信小程序提供wx.request()接口发送网络请求。这是一个非常常见的API。封装之后我们可以节省很多代码。
//不封装直接使用我们发送一个AJAX请求需要大量代码
wx.request({
url:"",
data:"数据",
method:"请求方式", //有GET、POST、PUT等值
dataType:"返回数据类型",//默认为json字符串
header:{
//请求头
},
success() {
//接口调用成功的回调函数
},
fail() {
//接口调用失败的回调函数
},
complete() {
//接口调用成功/失败都会执行的回调函数
}
});
复制代码
在utils文件夹下创建一个HTTP.js文件,将wx.request包装在这里
class HTTP {
constructor() {}
request(params) {
//默认值处理,url不允许为空
if(!params.url) {
console.log('url没有传入');
return;
}
//method默认为GET
if(!params.method) {
params.method='GET';
}
wx.request({
url:params.url,
method:params.method,
data:params.data,
header:{
'content-type':'application/json'
},
success:res=> {
let code=res.statusCode.toString().substr(0,1);
//http请求状态码为2开头的时候判断为请求成功
if(code==='2') {
params.success && params.success(res.data);
}
//状态码不为2开头如5开头的则判断为请求失败
else {
params.error && params.error(res.data);
}
},
fail:()=> {
console.log('ajax error');
}
});
}
};
export {HTTP};
复制代码
发送AJAX时,我们只需要提交url、数据即可,方法为GET时,success方法可以省略。错误方法。还有很多参数需要提交。至此,每个具体的AJAX请求就可以被封装起来了。
在models文件夹下创建首页发送AJAX的文件indexModels.js,这里是对首页使用的AJAX请求进行了第二次封装。
import {HTTP} from '../utils/HTTP.js';
import {IndexMock} from '../Mock/indexMock.js' ;
let indexMock=new IndexMock();
class IndexModels extends HTTP{
constructor (){
super();
}
//请求首页真实数据
getIndexList(data,success) {
let params={
url:'http://xxx.com/Index/List',
//请求数据使用GET请求,method不需要设置
data:data,
success:success
};
this.request(params);
}
//请求首页模拟数据
getIndexListByMock(data,success) {
let list=indexMock.getIndexList();
success && success(list);
}
}
export {IndexModels};
复制代码
页面引入indexModels.js文件后,新建一个类,调用getIndexListByMock方法。此时,您只需提交数据和成功方法即可。
2.5 简化Mock的副作用
使用Mock后,总是切换回真实数据。此时页面上的每一个AJAX请求都得修改,太麻烦了。在这种情况下,您可以考虑引入全局常量。只需更改此常量即可将模拟数据切换为真实数据。
在最外层创建一个config.js文件,定义一个常量来检查数据源是假数据还是真实数据。
const DEBUGGER=true;
export {DEBUGGER};
复制代码
在indexModels.js文件中引入config.js,不断使用DEBUGGER来确定使用哪个数据源。 IndexModels.js 修改为:
//DEBUGGER为true表示请求虚拟数据,为false表示请求真实数据
import {DEBUGGER} from '../config.js';
import {HTTP} from '../utils/HTTP.js';
import {IndexMock} from '../Mock/indexMock.js' ;
let indexMock=new IndexMock();
class IndexModels extends HTTP{
constructor (){
super();
}
//请求首页数据
getIndexList(data,success) {
if(!DEBUGGER) {//请求真实数据
let params={
url:'http://xxx.com/Index/List',
data:data,
success:success
};
this.request(params);
}
else {//请求虚拟数据
let list=indexMock.getIndexList();
success && success(list);
}
}
}
export {IndexModels};
复制代码
后面需要将数据源更改为真实数据时,只需在 config.js 中将数据源更改为真实数据即可,将 DEBUGGER 更改为 false 即可。这时候这个页面就写好了。
3 总结
该项目使用 OOP 思维,并使用了界面现在所需的许多技能。这是一个比较广泛的项目。
作者:再见骷髅王
链接:https://juejin.im/post/5cfb43306fb9a07eea3264a1
来源:掘金❝❀作者。商业转载请联系作者获取授权。非商业转载请注明来源。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。