前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·008【首页开发】
注:前言、目录见 https://god-excious.blog.csdn.net/article/details/105312456
文章目录
- 【024】page-json配置
- 【025】图文、视频和列表样式(上)
- 图片引入
- 设计细节
- 整体代码
- 【026】图文、视频和列表样式(下)
- 设计细节
- 整体代码
- 【027】封装列表样式组件
- 数据存储
- 状态(关注、赞、踩)标识
- 封装组件
- 【028】滚动tab导航开发
- 操作步骤
- 其他注意点
- 整体代码
- 【029】滚动tab导航开发(下)
- 注意点
- 详细代码
- 【030】封装滚动tab导航组件
- 步骤总结
- 详细代码
- 【031】上拉加载组件开发
- 流程简述
- 核心代码
- 效果图
- 【032】封装上拉加载组件
- 流程简述
- 核心代码
- 【033】优化图文列表组件
- 具体优化
- 组件代码
- 【034】封装无数据默认组件
- 具体优化
- 核心代码
- 效果图
【024】page-json配置
官方文档 https://uniapp.dcloud.io/collocation/pages?id=配置项列表
官方文档 https://uniapp.dcloud.io/collocation/pages?id=style
可以在page-json中配置一些样式,包括“导航栏”、“按钮”、“下拉刷新”等样式。
大多数内容可以到官方文档中找到,下面给出一种配置的样式
{"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages{"path": "pages/index/index","style": {// "navigationBarTitleText": "仿糗事百科""app-plus": {// 隐藏滚动条"scrollIndicator":"none",// 配置导航栏"titleNView": {// 配置搜索框"searchInput": {// 对齐方式(默认值center)"align": "center",// 背景色"backgroundColor": "#F7F7F7",// 边框圆角"borderRadius": "4px",// 提示文字"placeholder": "搜索糗事",// 阻止输入(一般都是阻止输入,点击后跳转到搜索页面)"disabled": "true"},// 配置按钮"buttons": [// 左边按钮{// 设置颜色"color": "#FF9619",// 设置按钮按下的颜色"colorPressed": "#BBBBBB",// 设置浮动"float": "left",// 设置按钮上文字大小"fontSize": "22px",// 设置字体文件的路径"fontSrc": "/static/font/icon.ttf",// 设置按钮上显示的文字"text": "\ue609"},// 右边按钮{"color": "#000000","colorPressed": "#BBBBBB","float": "right","fontSize": "22px","fontSrc": "/static/font/icon.ttf","text": "\ue653"}]}}}},{"path" : "pages/news/news","style" : {}},{"path" : "pages/paper/paper","style" : {}},{"path" : "pages/home/home","style" : {}}],"globalStyle": {"navigationBarTextStyle": "black","navigationBarTitleText": "仿糗事百科","navigationBarBackgroundColor": "#F8F8F8","backgroundColor": "#F8F8F8"},"tabBar": {"color":"#adadad", // 导航栏文字默认颜色"selectedColor":"#fee42a", // 导航栏选中颜色"backgroundColor":"#fff", // 导航栏背景颜色"borderStyle":"white", // 导航栏边框样式"list":[ // tab的列表{"pagePath":"pages/index/index", // 导航栏对应页面路径(不用写.vue)"text":"糗事", // 导航栏文字"iconPath":"static/tabbar/index.png", // 导航栏未选中的图标路径"selectedIconPath":"static/tabbar/indexed.png" // 导航栏已选中的图标路径},{"pagePath":"pages/news/news","text":"动态","iconPath":"static/tabbar/news.png","selectedIconPath":"static/tabbar/newsed.png"},{"pagePath":"pages/paper/paper","text":"小纸条","iconPath":"static/tabbar/paper.png","selectedIconPath":"static/tabbar/papered.png"},{"pagePath":"pages/home/home","text":"我的","iconPath":"static/tabbar/home.png","selectedIconPath":"static/tabbar/homed.png"}]}
}
注:
buttons
中字体的路径fontSrc
对应了图标项目中的iconfont.ttf文件的路径,一般将其引入到uni-app项目中的/static/font
文件夹下buttons
中提示文字text
,填写的内容为图标项目中demo_index.html打开后Unicode下,该图标的编号。例如:某图标在Unicode中编号为
,就应该填写"text": "\ue601"
,以此类推。
【025】图文、视频和列表样式(上)
图片引入
图片组件——官方文档 https://uniapp.dcloud.io/component/image
格式大致如下
<image src="../../static/demo/userpic/12.jpg" mode="widthFix" lazy-load></image>
属性 | 功能 |
---|---|
src
|
图片路径 |
mode
|
图片裁剪、缩放的模式(widthFix 代表宽度不变,高度自动变化,保持原图宽高比不变)
|
lazy-load
|
图片懒加载 |
设计细节
在设计时,需要注意以下一些细节
- 首先按照设计图,对某个区域可以分成若干行,我们把这些行都做成
class="网页名-list-i"
的view
组件,然后将它们放到一个class="网页名-list"
的view
组件中 - 像是头像、昵称这一组,或者是**+icon、关注这一组,都是水平方向上垂直居中排列的,可以把文字(直接写到父标签下,不一定要新建标签)、图像放到一个
view
组件下,然后以flex布局(默认主轴方向即可)设置交叉轴(纵向)居中——align-item: center;
**,即可在同一行上垂直居中排版 - 像是赞数、踩数这一组,或者是评论数、转发数这一组,水平方向上垂直居中和上面类似,还要设计好图标与文字之间的间距,可以给图标设置一个**
margin-right
,如果有多个图标和文字的组,并且排列在同一侧,可以给图标的父标签设置一个margin-right
**,让组与组之间保持间距。 - 设计图中的一些圆角不要忽略了
- 行与行之间的间距可以通过给类名为
网页名-list-i
的元素设置一个padding-top
,最后一个行元素可以考虑设置一个padding: ??px, 0;
让上下都保持一部分间距 - 整个区域内部的边缘地区若有少量间距,可以对整个区域的标签设置一个
padding
,显示出这样的空隙。 - 整个区域往下的分隔线,可以通过设置
border-bottom
属性实现 - 阿里巴巴矢量图库项目的图标引入,可以参考章节【010】
- 为了增强CSS代码复用性,可以把flex布局的相关代码提取出来,封装到common.css文件里去,一般根据flex布局的样式来起名,我们可以取出类似
u-f
、u-f-ac
、u-f-ajc
、u-f-jsb
这样的类名,然后给需要的标签加上这些类名。
整体代码
index.css文件
<template><view><view class="index-list"><view class="index-list1 u-f-ac u-f-jsb"><view class="u-f-ac"><image src="../../static/demo/userpic/12.jpg" mode="widthFix" lazy-load></image>昵称</view><view class="u-f-ac"><view class="icon iconfont icon-zengjia"></view>关注</view></view><view class="index-list2">这是标题</view><view class="index-list3"><image src="../../static/demo/datapic/11.jpg" mode="widthFix" lazy-load></image></view><view class="index-list4 u-f-ac u-f-jsb"><view class="u-f-ac"><view class="u-f-ac"><view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>10</view><view class="u-f-ac"><view class="icon iconfont icon-kulian u-f-ac"></view>10</view></view><view class="u-f-ac"><view class="u-f-ac"><view class="icon iconfont icon-pinglun1 u-f-ac"></view>10</view><view class="u-f-ac"><view class="icon iconfont icon-zhuanfa u-f-ac"></view>10</view></view></view></view></view> </template><script>export default {data() {return {title: 'Hello'}},onLoad() {},methods: {}} </script><style>/* common.css在App.vue文件中引入了进来 */.index-list {padding: 20upx;border-bottom: 1upx solid #EEEEEE;}.index-list1>view:first-child {color: #999999;}.index-list1>view:first-child image {width: 90upx;height: 90upx;border-radius: 50%;margin-right: 10upx;}.index-list1>view:last-child { background-color: #F4F4F4;border-radius: 5upx;padding: 0 10upx;}.index-list2 {padding-top: 15upx;font-size: 32upx;}.index-list3 {padding-top: 15upx;}.index-list3>image {width: 100%;border-radius: 20upx;}.index-list4 {padding: 15upx 0;}.index-list4>view {color: #999999;}.index-list4>view>view:first-child, .index-list4>view>view>view {margin-right: 10upx;} </style>
common.css文件
/* 代表flex布局 */ .u-f, .u-f-ac, .u-f-ajc, .u-f-jsb {display: flex; }.u-f-ac, .u-f-ajc {align-items: center; }.u-f-ajc {justify-content: center; }.u-f-jsb {justify-content: space-between; }
App.vue文件
<script>export default {onLaunch: function() {console.log('App Launch')},onShow: function() {console.log('App Show')},onHide: function() {console.log('App Hide')}} </script><style>/*每个页面公共css */@import './common/uni.css';@import './common/icon.css';@import './common/animate.css';@import './common/common.css'; </style>
pages.json文件
和上一节一样
效果图
【026】图文、视频和列表样式(下)
设计细节
在设计时,有以下一些细节
- 要让某个组件显示在另一个组件之上,可以把他们放到同一个父组件下,然后对父组件用
postion: relative;
,对子组件用postion: absolute;
。然后如果需要显示在父组件的正中央,可以给父组件设置一个class="u-f-ajc"
;如果需要显示在父组件的边上,可以设置right
、left
、top
、bottom
其中的不同方向上的两个。 - 如果需要调节带透明的背景色,可以到Chrome浏览器中打开开发者工具,随便找一个元素,添加属性
color
,然后点击对应的颜色,拖动透明度条,进行调节,如果需要rgba
,点击上下切换的小箭头切换,然后把color
属性里的rgba
值复制过来。 - 对于阿里巴巴矢量图标库项目中,通过添加类名引入的图标,如果要设置其大小,只需要设置
font-size
属性即可。
整体代码
index.vue文件
和上一节课相比,主要增加、改动的地方是17~21行、94行、115~130行
<template><view><view class="index-list"><view class="index-list1 u-f-ac u-f-jsb"><view class="u-f-ac"><image src="../../static/demo/userpic/12.jpg" mode="widthFix" lazy-load></image>昵称</view><view class="u-f-ac"><view class="icon iconfont icon-zengjia"></view>关注</view></view><view class="index-list2">这是标题</view><view class="index-list3 u-f-ajc"><!-- 图片 --><image src="../../static/demo/datapic/11.jpg" mode="widthFix" lazy-load></image><!-- 视频 --><view class="index-list-play icon iconfont icon-bofang"></view><view class="index-list-playinfo">20w次播放 2:17</view></view><view class="index-list4 u-f-ac u-f-jsb"><view class="u-f-ac"><view class="u-f-ac"><view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>10</view><view class="u-f-ac"><view class="icon iconfont icon-kulian u-f-ac"></view>10</view></view><view class="u-f-ac"><view class="u-f-ac"><view class="icon iconfont icon-pinglun1 u-f-ac"></view>10</view><view class="u-f-ac"><view class="icon iconfont icon-zhuanfa u-f-ac"></view>10</view></view></view></view></view> </template><script>export default {data() {return {title: 'Hello'}},onLoad() {},methods: {}} </script><style>.index-list {padding: 20upx;border-bottom: 1upx solid #EEEEEE;}.index-list1>view:first-child {color: #999999;}.index-list1>view:first-child image {width: 90upx;height: 90upx;border-radius: 50%;margin-right: 10upx;}.index-list1>view:last-child { background-color: #F4F4F4;border-radius: 5upx;padding: 0 10upx;}.index-list2 {padding-top: 15upx;font-size: 32upx;}.index-list3 {position: relative;padding-top: 15upx;}.index-list3>image {width: 100%;border-radius: 20upx;}.index-list4 {padding: 15upx 0;}.index-list4>view {color: #999999;}.index-list4>view>view:first-child, .index-list4>view>view>view {margin-right: 10upx;}.index-list-play {position: absolute;font-size: 140upx;color: #FFFFFF;}.index-list-playinfo {position: absolute;background-color: rgba(51, 51, 51, 0.62);color: #FFFFFF;bottom: 8upx;right: 8upx;border-radius: 40upx;font-size: 22upx;padding: 0 12upx;} </style>
其他文件
和上一小节相同,不再重复
效果图
【027】封装列表样式组件
数据存储
在script
脚本的data()
中,用数组将页面中出现的数据封装成一个个对象
<script>export default {data() {return {list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]}},onLoad() {},methods: {}}
</script>
因为有可能存在多个对象,所以需要列表渲染(循环),详细代码见下面一小段。
状态(关注、赞、踩)标识
“是否关注”这一状态可以完全放到list
对象中一个对象的一个布尔变量来标识,用v-show
进行条件渲染。
“是否点赞、是否点踩”这些状态,和点赞数、点踩数一起放到list
对象中一个对象的一个infonum
里,状态用index
来标识,值为0
代表“未操作”,值为1
代表“点了赞”,值为2
代表“点了踩”。然后在:class
属性中根据一个条件表达式选择判断是否获得点击后的类名active
的样式。
<template><view><block v-for="(item, index) in list" :key="index"><view class="index-list"><view class="index-list1 u-f-ac u-f-jsb"><view class="u-f-ac"><image :src="item.userpic" mode="widthFix" lazy-load></image>{{item.username}}</view><!-- v-if会导致一点布局异常,还是用v-show好一些 --><view class="u-f-ac" v-show="item.isguanzhu"><view class="icon iconfont icon-zengjia"></view>关注</view></view><view class="index-list2">{{item.title}}</view><view class="index-list3 u-f-ajc"><!-- 图片 --><image :src="item.titlepic" mode="widthFix" lazy-load></image><!-- 视频 --><template v-if="item.type=='video'"><view class="index-list-play icon iconfont icon-bofang"></view><view class="index-list-playinfo">{{item.playnum}}次播放 {{item.long}}</view></template></view><view class="index-list4 u-f-ac u-f-jsb"><view class="u-f-ac"><view class="u-f-ac" :class="{'active':(item.infonum.index==1)}"><view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>{{item.infonum.dingnum}}</view><view class="u-f-ac" :class="{'active':(item.infonum.index==2)}"><view class="icon iconfont icon-kulian u-f-ac"></view>{{item.infonum.cainum}}</view></view><view class="u-f-ac"><view class="u-f-ac"><view class="icon iconfont icon-pinglun1 u-f-ac"></view>{{item.commentnum}}</view><view class="u-f-ac"><view class="icon iconfont icon-zhuanfa u-f-ac"></view>{{item.sharenum}}</view></view></view></view></block></view>
</template><script>export default {data() {return {list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]}},onLoad() {},methods: {}}
</script><style>.index-list {padding: 20upx;border-bottom: 1upx solid #EEEEEE;}.index-list1>view:first-child {color: #999999;}.index-list1>view:first-child image {width: 90upx;height: 90upx;border-radius: 50%;margin-right: 10upx;}.index-list1>view:last-child { background-color: #F4F4F4;border-radius: 5upx;padding: 0 10upx;}.index-list2 {padding-top: 15upx;font-size: 32upx;}.index-list3 {position: relative;padding-top: 15upx;}.index-list3>image {width: 100%;border-radius: 20upx;}.index-list4 {padding: 15upx 0;}.index-list4>view {color: #999999;}.index-list4>view>view:first-child, .index-list4>view>view>view {margin-right: 10upx;}.index-list-play {position: absolute;font-size: 140upx;color: #FFFFFF;}.index-list-playinfo {position: absolute;background-color: rgba(51, 51, 51, 0.62);color: #FFFFFF;bottom: 8upx;right: 8upx;border-radius: 40upx;font-size: 22upx;padding: 0 12upx;}.index-list4 .active, .index-list4 .active > view{color: #C5F61C;}</style>
效果图
封装组件
像是上面我们做好的一个list样式,就可以封装起来。
封装的步骤如下:
创建好一个components文件夹,然后右键新建组件,在components文件夹下再创建一个index文件夹,把之前新建好的组件文件index-list.vue文件放到index文件夹下
将index.vue文件中block标签下的所有标签剪切,放到index-list.vue文件中对应位置
将index.vue文件中
style
下的所有样式剪切,放到index-list.vue文件中对应位置。注:最好给里面的
style
加上一个属性scoped
,避免在引入组件样式后污染原本设置好的其他样式在index-list.vue文件的
script
下的props
中,定义需要传入的变量及其类型,像是这里就需要将循环中的item
和index
传进来,形式为变量名: 类型
在index.vue文件的
script
的export default
前,将组件文件引入进来,形如:import indexList from "../../components/index/index-list.vue";
注:将中划线命名改写为小驼峰命名
在index.vue文件的
script
的components
中,注册相应的组件以标签形式将组件进行引入,在属性中传入需要的参数,形如:
<block v-for="(item, index) in list" :key="index"><index-list :item="item" :index="index"></index-list> </block>
封装后的项目代码文件如下:
index.vue文件
<template><view><block v-for="(item, index) in list" :key="index"><index-list :item="item" :index="index"></index-list></block></view> </template><script>import indexList from "../../components/index/index-list.vue";export default {components: {indexList},data() {return {list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]}},onLoad() {},methods: {}} </script><style></style>
index-list.vue文件
<template><view class="index-list"><view class="index-list1 u-f-ac u-f-jsb"><view class="u-f-ac"><image :src="item.userpic" mode="widthFix" lazy-load></image>{{item.username}}</view><!-- v-if会导致一点布局异常,还是用v-show好一些 --><view class="u-f-ac" v-show="item.isguanzhu"><view class="icon iconfont icon-zengjia"></view>关注</view></view><view class="index-list2">{{item.title}}</view><view class="index-list3 u-f-ajc"><!-- 图片 --><image :src="item.titlepic" mode="widthFix" lazy-load></image><!-- 视频 --><template v-if="item.type=='video'"><view class="index-list-play icon iconfont icon-bofang"></view><view class="index-list-playinfo">{{item.playnum}}次播放 {{item.long}}</view></template></view><view class="index-list4 u-f-ac u-f-jsb"><view class="u-f-ac"><view class="u-f-ac" :class="{'active':(item.infonum.index==1)}"><view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>{{item.infonum.dingnum}}</view><view class="u-f-ac" :class="{'active':(item.infonum.index==2)}"><view class="icon iconfont icon-kulian u-f-ac"></view>{{item.infonum.cainum}}</view></view><view class="u-f-ac"><view class="u-f-ac"><view class="icon iconfont icon-pinglun1 u-f-ac"></view>{{item.commentnum}}</view><view class="u-f-ac"><view class="icon iconfont icon-zhuanfa u-f-ac"></view>{{item.sharenum}}</view></view></view></view> </template><script>export default {props: {item: Object,index: Number}} </script><style scoped>.index-list {padding: 20upx;border-bottom: 1upx solid #EEEEEE;}.index-list1>view:first-child {color: #999999;}.index-list1>view:first-child image {width: 90upx;height: 90upx;border-radius: 50%;margin-right: 10upx;}.index-list1>view:last-child { background-color: #F4F4F4;border-radius: 5upx;padding: 0 10upx;}.index-list2 {padding-top: 15upx;font-size: 32upx;}.index-list3 {position: relative;padding-top: 15upx;}.index-list3>image {width: 100%;border-radius: 20upx;}.index-list4 {padding: 15upx 0;}.index-list4>view {color: #999999;}.index-list4>view>view:first-child, .index-list4>view>view>view {margin-right: 10upx;}.index-list-play {position: absolute;font-size: 140upx;color: #FFFFFF;}.index-list-playinfo {position: absolute;background-color: rgba(51, 51, 51, 0.62);color: #FFFFFF;bottom: 8upx;right: 8upx;border-radius: 40upx;font-size: 22upx;padding: 0 12upx;}.index-list4 .active, .index-list4 .active > view{color: #C5F61C;} </style>
其他文件
和之前基本一样
效果图
和上一段展示的效果图一样
【028】滚动tab导航开发
操作步骤
根据uni-app-hello项目中的tabbar.vue文件,依次进行以下操作:
- 将uni-app-hello项目中的uni.css文件引入,方法可以参考【009】
- 将导航栏的文字内容以若干组
{name: "??", id: "??"}
的形式,写到data
中的数组tabBars
下。 - 在外层创建一个
class="uni-tab-bar"
的view
组件 - 在上述
view
组件下创建一个class="uni-swiper-tab" scroll-x
的scroll-view
组件 - 在上述
scroll-view
组件下创建一个block
组件,属性为v-for="(tab,index) in tabBars" :key="tab.id"
,列表渲染class="swiper-tab-list"
的view
组件 - 每一个被列表渲染的
view
组件内容显示{{tab.name}}
其他注意点
有如下注意点:
- 如果需要设置导航栏中当前选中项的样式,可以对被列表渲染的
view
组件设置:class="{'active': tabIndex==index}"
- 如果需要设置导航栏中某一项被点击后成为当前选中项,可以先在
data
中设置tabIndex
值(先设置为0代表初始选中第一个),然后在methods
中设置一个处理函数tabtap(index)
,内容就是this.tabIndex=index;
,最后放到被列表渲染的view
组件上用@tap="tabtap(index)"
绑定事件处理 - 可以对
.uni-swiper-tab
的scroll-view
组件设置border-bottom
属性,调整导航栏分隔线的样式 - 可以对
.swiper-tab-list
的列表渲染view
组件设置文字的样式 - 可以对
.uni-tab-bar
下的.active
的列表渲染view
组件设置被选中后的文字样式 - 如果要添加被选中后文字下方出现下划线的样式,可以在被列表渲染的
view
组件下再加一个class="swiper-tab-line"
的view
组件,然后对.active
下的.swiper-tab-line
设置类似border-botom
、margin: 0 auto;
、border-radius
等等样式
整体代码
以下仅展示index.vue文件的代码
<template><view><view class="uni-tab-bar"><scroll-view scroll-x class="uni-swiper-tab"><block v-for="(tab, index) in tabBars" :key="tab.id"><view class="swiper-tab-list" :class="{'active': tabIndex==index}" @tap="tabtap(index)">{{tab.name}}<view class="swiper-tab-line"></view></view></block></scroll-view></view><!-- <block v-for="(item, index) in list" :key="index"><index-list :item="item" :index="index"></index-list></block> --></view>
</template><script>import indexList from "../../components/index/index-list.vue";export default {components: {indexList},data() {return {tabIndex: 0,tabBars: [{name: "关注", id: "guanzhu"},{name: "推荐", id: "tuijian"},{name: "体育", id: "tiyu"},{name: "热点", id: "redian"},{name: "财经", id: "caijing"},{name: "娱乐", id: "yule"}],list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]}},onLoad() {},methods: {tabtap(index){this.tabIndex=index;}}}
</script><style>.swiper-tab-list {color: #969696;font-weight: bold;}.uni-swiper-tab {border-bottom: 1upx solid #EEEEEE;}.uni-tab-bar .active {color: #343434;}/* 被选中才出现下划线 */.active .swiper-tab-line {border-bottom: 6upx solid #FEDE33;width: 70upx;margin: 0 auto;border-top: 6upx solid #FEDE33;border-radius: 20upx;}
</style>
效果图
【029】滚动tab导航开发(下)
swiper
组件·官方文档 https://uniapp.dcloud.io/component/swiper
获取系统信息·官方文档 https://uniapp.dcloud.io/api/system/info
注意点
- 创建数组数据
newslist
,里面是6个list
对象,分别与滚动栏上的6个种类对应 - 为了能够让能容横向滚动,和上一节类似地在
class="uni-tab-bar"
的view
组件中使用了class="swiper-box"
的swiper
组件,在swiper
组件下用swiper-item
组件对数组newslist
进行列表渲染,然后在swiper-item
组件下用scroll-view
组件创建滚动条,滚动条内将之前的内容block
组件放入,大致就完成了 - 为了获取运行的系统的相关信息(如:系统的屏幕尺寸、显示尺寸……),可以在
script
下的onLoad()
中用uni.getSystemInfo({ success:(res)=> { } })
在函数体中用res.windowHeight
获取显示高度(其他属性见上面给出的官方文档) - 如果要调节自适应的大小,可以变量
swiperheight
存储大小对应的px
值,然后给swiper
组件设置相应尺寸的style
(因为upx
不支持在style
中动态绑定)。swiperheight
的计算应该放到onLoad()
中的uni.getSystemInfo
里,然后把结果传入这个变量值中。由于在uin.css文件中,.uni-tab-bar
、.swiper-box
的height
被计算为calc(100% - 100upx)
,我们可以用类似的方法,计算出this.swiperheight=res.windowHeight-uni.upx2px(100);
,这样的高度是差不多就是可以自适应的。 - 给
swiper
组件设置:current:"tabIndex";
可以让横向滚动时,显示出对应的列表内容。 - 给
swiper
组件设置@change="tabChange"
,然后定义好函数tabChange
,里面有默认参数event
(调用时不用加上括号和参数列表),函数的内容定义this.tabIndex=e.detail.current;
,这样可以设置横向滚动时,让导航栏也一起随之变化
详细代码
<template><view><view class="uni-tab-bar"><scroll-view scroll-x class="uni-swiper-tab"><block v-for="(tab, index) in tabBars" :key="tab.id"><view class="swiper-tab-list" :class="{'active': tabIndex==index}" @tap="tabtap(index)">{{tab.name}}<view class="swiper-tab-line"></view></view></block></scroll-view></view><view class="uni-tab-bar"><swiper class="swiper-box" :style="{height: swiperheight+'px'}" :current="tabIndex" @change="tabChange"><swiper-item v-for="(items, index) in newslist" :key="index"><scroll-view scroll-y class="list"><block v-for="(item, index1) in items.list" :key="index1"><index-list :item="item" :index="index1"></index-list></block></scroll-view></swiper-item></swiper></view></view>
</template><script>import indexList from "../../components/index/index-list.vue";export default {components: {indexList},data() {return {swiperheight: 500,tabIndex: 0,tabBars: [{name: "关注", id: "guanzhu"},{name: "推荐", id: "tuijian"},{name: "体育", id: "tiyu"},{name: "热点", id: "redian"},{name: "财经", id: "caijing"},{name: "娱乐", id: "yule"}],newslist: [{list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]},{list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]},{list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]},{list:[]},{list:[]},{list:[]}]}},onLoad() {uni.getSystemInfo({success:(res)=> {let height = res.windowHeight-uni.upx2px(100);this.swiperheight=height;}});},methods: {// tabBar点击事件tabtap(index) {this.tabIndex=index;},// 滑动联动切换导航栏tabChange(e) {// console.log(JSON.stringify(e.detail));this.tabIndex=e.detail.current;}}}
</script><style>.swiper-tab-list {color: #969696;font-weight: bold;}.uni-swiper-tab {border-bottom: 1upx solid #EEEEEE;}.uni-tab-bar .active {color: #343434;}/* 被选中才出现下划线 */.active .swiper-tab-line {border-bottom: 6upx solid #FEDE33;width: 70upx;margin: 0 auto;border-top: 6upx solid #FEDE33;border-radius: 20upx;}
</style>
【030】封装滚动tab导航组件
步骤总结
步骤如下:
- 首先还是和以前一样,在components文件夹下的index文件夹下,新建swiper-tab-head.vue文件,将导航栏部分代码剪切过来,将样式部分代码剪切过来,将点击处理的方法剪切过来,在swiper-tab-head.vue文件的
props
中定义好要使用到的变量,在index.vue文件中用自定义的swiper-tab-head
组件将导航栏引入,然后以:tabBars="tabBars" :tabIndex="tabIndex"
的方式传入相关变量 - 但是仅仅是上面这样还不够,因为点击事件的方法调用在子组件里,没有修改到父组件里面的变量值,因此要在子组件里将点击事件的处理改成
this.$emit('tabtap', index);
,意思是监听一个自定义的名为'tabtap'
的事件、然后把index
传过去,然后在父组件里通过设置属性@tabtap="tabtap"
,意思是当触发了tabtap
事件后、将子组件中通过tabtap
事件传入的index
作为参数、传入父组件的函数tabtap
中、进行事件处理,从而达到父子组件通信的效果。
详细代码
index.vue文件
<template><view><swiper-tab-head :tabBars="tabBars" :tabIndex="tabIndex" @tabtap="tabtap"></swiper-tab-head><view class="uni-tab-bar"><swiper class="swiper-box" :style="{height: swiperheight+'px'}" :current="tabIndex" @change="tabChange"><swiper-item v-for="(items, index) in newslist" :key="index"><scroll-view scroll-y class="list"><block v-for="(item, index1) in items.list" :key="index1"><index-list :item="item" :index="index1"></index-list></block></scroll-view></swiper-item></swiper></view></view> </template><script>import indexList from "../../components/index/index-list.vue";import swiperTabHead from "../../components/index/swiper-tab-head.vue";export default {// 注册组件components: {indexList,swiperTabHead},data() {return {swiperheight: 500,tabIndex: 0,tabBars: [{name: "关注", id: "guanzhu"},{name: "推荐", id: "tuijian"},{name: "体育", id: "tiyu"},{name: "热点", id: "redian"},{name: "财经", id: "caijing"},{name: "娱乐", id: "yule"}],newslist: [{list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]},{list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]},{list:[{// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},{userpic: "../../static/demo/userpic/12.jpg",username: "昵称",isguanzhu: true,title: "这是标题",type: "video",titlepic: "../../static/demo/datapic/11.jpg",// 播放次数playnum: "2w",long: "2:47",infonum: {index: 2,dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10},]},{list:[]},{list:[]},{list:[]}]}},onLoad() {uni.getSystemInfo({success:(res)=> {let height = res.windowHeight-uni.upx2px(100);this.swiperheight=height;}});},methods: {// tabBar点击事件tabtap(index) {this.tabIndex=index;},// 滑动联动切换导航栏tabChange(e) {// console.log(JSON.stringify(e.detail));this.tabIndex=e.detail.current;}}} </script><style></style>
swiper-tab-head文件
<template><view class="uni-tab-bar"><scroll-view scroll-x class="uni-swiper-tab"><block v-for="(tab, index) in tabBars" :key="tab.id"><view class="swiper-tab-list" :class="{'active': tabIndex==index}" @tap="tabtap(index)">{{tab.name}}<view class="swiper-tab-line"></view></view></block></scroll-view></view> </template><script>export default {props: {tabBars: Array,tabIndex: Number},methods: {// tabBar点击事件tabtap(index) {this.$emit('tabtap', index);},}} </script><style>.swiper-tab-list {color: #969696;font-weight: bold;}.uni-swiper-tab {border-bottom: 1upx solid #EEEEEE;}.uni-tab-bar .active {color: #343434;}/* 被选中才出现下划线 */.active .swiper-tab-line {border-bottom: 6upx solid #FEDE33;width: 70upx;margin: 0 auto;border-top: 6upx solid #FEDE33;border-radius: 20upx;} </style>
其余文件
其余文件和之前的项目文件大致相同
【031】上拉加载组件开发
流程简述
- 在
swiper
组件下的swiper-item
组件下的scroll-view
组件下增加一个view
组件,用于上拉加载 - 给
swiper
组件下的swiper-item
组件下的scroll-view
组件的scrolltolower
事件绑定一个自定义函数loadmore(index)
loadmore
函数中,先根据newslist[index].loadtext
的内容判断加载状态,如果不是待加载状态,就不进行加载- 加载前将状态调整至加载中,加载到的数据追加到
newslist[index].list
中,然后再把加载状态调整至待加载 - 没有更多数据的状态以后再讨论
核心代码
<template><view><!-- ...... --> <view class="uni-tab-bar"><swiper class="swiper-box" :style="{height: swiperheight+'px'}" :current="tabIndex" @change="tabChange"><swiper-item v-for="(items, index) in newslist" :key="index"><scroll-view scroll-y class="list" @scrolltolower="loadmore(index)"><!-- 图文列表 --><block v-for="(item, index1) in items.list" :key="index1"><index-list :item="item" :index="index1"></index-list></block><!-- 上拉加载 --><view class="load-more">{{items.loadtext}}</view></scroll-view></swiper-item></swiper></view></view>
</template><script>import indexList from "../../components/index/index-list.vue";import swiperTabHead from "../../components/index/swiper-tab-head.vue";export default {// 注册组件components: {indexList,swiperTabHead},data() {return {//......newslist: [{loadtext: "上拉加载更多",list:[{//......},{//......},]},{loadtext: "上拉加载更多",list:[{//......},{//......},{//......},{//......},]},{loadtext: "上拉加载更多",list:[{//......},{//......},]},{loadtext: "上拉加载更多",list:[]},{loadtext: "上拉加载更多",list:[]},{loadtext: "上拉加载更多",list:[]}]}},onLoad() {//......},methods: {//......// 上拉加载状态loadmore(index) {// 三种状态// this.newslist[index].loadtext='上拉加载更多';// this.newslist[index].loadtext='加载中';// this.newslist[index].loadtext='没有更多数据了';// 正在加载中或者没有更多数据的时候不会向服务器发送请求if (this.newslist[index].loadtext!=='上拉加载更多') {return;}// 模拟请求数据this.newslist[index].loadtext='加载中'; // 修改状态setTimeout(()=> {// 获取完成let obj = {// 用户头像userpic: "../../static/demo/userpic/12.jpg",// 用户名username: "昵称",// 关注情况isguanzhu: false,// 标题title: "这是标题",// 类型(img-图文,video-视频)type: "img",// 封面图titlepic: "../../static/demo/datapic/11.jpg",// 赞、踩数,标记情况infonum: {index: 1, // 0-无操作,1-顶了,2-踩了dingnum: 11,cainum: 11,},commentnum: 10,sharenum: 10};this.newslist[index].list.push(obj); // 加入数组this.newslist[index].loadtext='上拉加载更多'; // 修改状态}, 1000);},//......}
</script><style>.load-more {text-align: center;color: #AAAAAA;padding: 15upx 0;}
</style>
效果图
【032】封装上拉加载组件
流程简述
之前其实也描述过了封装的一般流程 点这里
这里再来描述一下:
- 在components文件夹下新建common文件夹代表这个组件是多页面通用的
- 在common文件夹下新建一个页面(这里就是load-more.vue)
- 将要封装的部分(这里就是
<view class="load-more">{{items.loadtext}}</view>
),剪切粘贴到刚才新建的页面中 - 将对应的样式(这里就是
.load-more
的样式)剪切粘贴到刚才新建的页面中 - 将刚刚剪切的组件中要用到的数据在
props
中注册,然后再把组件中使用的变量换成相应的变量名 - 在原来的页面中通过
import 小驼峰名 from ".vue文件路径"
- 在原来的页面中通过
commponents
注册相应的组件 - 在原来的页面中原来的组件的位置,使用自定义的组件,如果要传参数可以用
:变量名="具体变量"
的形式传入
核心代码
index.vue文件
<template><view><!-- ...... --><view class="uni-tab-bar"><!-- ...... --><!-- ...... --><!-- ...... --><!-- 上拉加载 --><load-more :loadtext="items.loadtext"></load-more><!-- ...... --><!-- ...... --><!-- ...... --></view></view> </template><script>//......import loadMore from "../../components/common/load-more.vue";export default {// 注册组件components: {//......loadMore},data() {//......},onLoad() {//......},methods: {// 上拉加载状态loadmore(index) {//......}, </script><style></style>
load-more.vue文件
<template><view class="load-more">{{loadtext}}</view> </template><script>export default {props: {loadtext: String}} </script><style scoped>.load-more {text-align: center;color: #AAAAAA;padding: 15upx 0;} </style>
【033】优化图文列表组件
具体优化
- 点击【关注】之后将不再出现【关注】按钮(个人感觉这个可以优化为已关注,方便快速取关)
- 点击【顶】、【踩】之后,相应的数据会进行修改,相关的状态会进行调整
- 点击【文章标题】、【文章图片】之后,会跳转到相应的详情页(这里先写一个接口,只打印一下提示,以后再做具体实现)
组件代码
(index-list组件)
<template><view class="index-list animated rollIn"><view class="index-list1 u-f-ac u-f-jsb"><view class="u-f-ac"><image :src="item.userpic" mode="widthFix" lazy-load></image>{{item.username}}</view><!-- v-if会导致一点布局异常,还是用v-show好一些 --><view class="u-f-ac" v-show="!item.isguanzhu" @tap="guanzhu"><view class="icon iconfont icon-zengjia"></view>关注</view></view><view class="index-list2" @tap="opendetail">{{item.title}}</view><view class="index-list3 u-f-ajc" @tap="opendetail"><!-- 图片 --><image :src="item.titlepic" mode="widthFix" lazy-load></image><!-- 视频 --><template v-if="item.type=='video'"><view class="index-list-play icon iconfont icon-bofang"></view><view class="index-list-playinfo">{{item.playnum}}次播放 {{item.long}}</view></template></view><view class="index-list4 u-f-ac u-f-jsb"><view class="u-f-ac"><view class="u-f-ac" :class="{'active':(item.infonum.index==1)}" @tap="caozuo('ding')"><view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>{{item.infonum.dingnum}}</view><view class="u-f-ac" :class="{'active':(item.infonum.index==2)}" @tap="caozuo('cai')"><view class="icon iconfont icon-kulian u-f-ac"></view>{{item.infonum.cainum}}</view></view><view class="u-f-ac"><view class="u-f-ac"><view class="icon iconfont icon-pinglun1 u-f-ac"></view>{{item.commentnum}}</view><view class="u-f-ac"><view class="icon iconfont icon-zhuanfa u-f-ac"></view>{{item.sharenum}}</view></view></view></view>
</template><script>export default {props: {item: Object,index: Number},methods: {// 关注guanzhu() {this.item.isguanzhu = true;uni.showToast({title: "关注成功"});},// 顶踩caozuo(type) {switch(type) {case 'ding':if (this.item.infonum.index === 1) { // 已经顶了(取消顶)--this.item.infonum.dingnum;this.item.infonum.index = 0;} else if (this.item.infonum.index === 2) { // 已经踩了(取消踩,顶)++this.item.infonum.dingnum;--this.item.infonum.cainum;this.item.infonum.index = 1;} else { // 未操作(顶)++this.item.infonum.dingnum;this.item.infonum.index = 1;}break;case 'cai':if (this.item.infonum.index === 2) { // 已经踩了(取消踩)--this.item.infonum.cainum;this.item.infonum.index = 0;} else if (this.item.infonum.index === 1) { // 已经顶了(取消顶,踩)++this.item.infonum.cainum;--this.item.infonum.dingnum;this.item.infonum.index = 2;} else { // 未操作(踩)++this.item.infonum.cainum;this.item.infonum.index = 2;}break;}},// 进入详情页opendetail() {// 暂时留一个接口,先不做具体实现console.log("进入详情页");}},}
</script><style scoped>.index-list {padding: 20upx;border-bottom: 1upx solid #EEEEEE;}.index-list1>view:first-child {color: #999999;}.index-list1>view:first-child image {width: 90upx;height: 90upx;border-radius: 50%;margin-right: 10upx;}.index-list1>view:last-child { background-color: #F4F4F4;border-radius: 5upx;padding: 0 10upx;}.index-list2 {padding-top: 15upx;font-size: 32upx;}.index-list3 {position: relative;padding-top: 15upx;}.index-list3>image {width: 100%;border-radius: 20upx;}.index-list4 {padding: 15upx 0;}.index-list4>view {color: #999999;}.index-list4>view>view:first-child, .index-list4>view>view>view {margin-right: 10upx;}.index-list-play {position: absolute;font-size: 140upx;color: #FFFFFF;}.index-list-playinfo {position: absolute;background-color: rgba(51, 51, 51, 0.62);color: #FFFFFF;bottom: 8upx;right: 8upx;border-radius: 40upx;font-size: 22upx;padding: 0 12upx;}.index-list4 .active, .index-list4 .active > view{color: #C5F61C;}
</style>
【034】封装无数据默认组件
具体优化
对于无数据的页面,优化了展示的效果,不再是几乎一片空白,并将组件进行了封装。
核心代码
index.vue文件
<template><view><swiper-tab-head :tabBars="tabBars" :tabIndex="tabIndex" @tabtap="tabtap"></swiper-tab-head><view class="uni-tab-bar"><!-- ...... --><!-- ...... --><!-- ...... --><template v-if="items.list.length > 0"><!-- 图文列表 --><block v-for="(item, index1) in items.list" :key="index1"><index-list :item="item" :index="index1"></index-list></block><!-- 上拉加载 --><load-more :loadtext="items.loadtext"></load-more></template><template v-else><!-- 无内容默认 --><nothing></nothing></template><!-- ...... --><!-- ...... --><!-- ...... --></view></view> </template><script>//......import nothing from "../../components/common/nothing.vue";export default {// 注册组件components: {//......nothing},data() {return {//......}},onLoad() {//......},methods: {//......}} </script><style></style>
nothing.vue文件
<template><view class="nothing u-f-ajc animated fadeIn"><image src="../../static/common/nothing.png" mode="widthFix"></image></view> </template><script> </script><style>.nothing {position: absolute;left: 0;right: 0;top: 0;bottom: 0;}.nothing > image {width: 50%;} </style>
效果图
前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·008【首页开发】相关推荐
- 前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·000【前言】
前言 本系列笔记,基于曾经的网易云课堂上一个"uni-app仿糗事百科"开发的课程,课程的资源来自网络. 我仅做一些笔记,来记录学习的一些收获. 前8节课讲的都是一些软件的基础使用 ...
- 前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·006【底部导航开发】
注:前言.目录见 https://god-excious.blog.csdn.net/article/details/105312456 文章目录 [013]底部导航开发 [013]底部导航开发 官方 ...
- 前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·005【设置全局属性globalStyle】
注:前言.目录见 https://god-excious.blog.csdn.net/article/details/105312456 文章目录 [012]设置全局样式globestyle [012 ...
- 前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·009【搜索页开发】
注:前言.目录见 https://god-excious.blog.csdn.net/article/details/105312456 文章目录 [035]搜索页开发(上) 开发内容 具体方法 核心 ...
- 前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·004【App.vue引入全局公共样式】
注:前言.目录见 https://god-excious.blog.csdn.net/article/details/105312456 文章目录 [009]引入官方CSS样式库 [010]引入第三方 ...
- 前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·007【uni-app和vue.js基础快速上手】
注:前言.目录见 https://god-excious.blog.csdn.net/article/details/105312456 文章目录 [014]view和text组件和动画使用 常见的尺 ...
- 高仿糗事百科学习(三)NET
高仿糗事百科,是一个典型的cs模式,所以我们获取数据就要通过net,今天我就开始书写关于网络连接方面的书写. 在安卓中,我们将联网请求往往是放在次线程中,如果放在主线程中,将会导致主线程要处理事件太多 ...
- uniapp实战项目仿糗事百科_项目设计最好用的底层思考模型——黄金圈
为什么要学习黄金圈法则 如何学习黄金圈法则 学习黄金圈法则哪些内容 彩蛋 全文共计2200字,10张图片I阅读13分钟 为什么要学习黄金圈法则 在工作中和生活中,你是否遇到过以下的困惑: 1-老板突然 ...
- 最新uni-app实战仿糗事百科app开发教程完整版
课程概述: 本季度为uni-app实战项目第一季度,将实战开发仿糗事百科app,其中会包括发布到安卓端app,IOS端app.微信小程序和支付宝小程序. 章节1项目介绍(买前必看) 课时1项目介绍(买 ...
最新文章
- CNCF案例研究:奇虎360
- 如何关闭360自定义错误页面
- SAP--DEBUG--外部断点的设置
- 5.11 学习日记,首页banner做好了
- 容器编排技术 -- 使用Minikube在Kubernetes中运行应用
- 江苏师范大学计算机控制考试题库,江苏技术师范学院2006¬—2007学年第2学期《微机原理与接口技术》试卷(2份,有答案)...
- Go语言中的单引号、双引号、反引号
- delphi7+firebird+dbexpress
- 无线收发模块——NRF24L01
- 自我时间管理与时间意识
- ppm\℃是什么意思/
- Javascript飘窗代码
- 通过PS的图层样式制作透明的玻璃字
- 基于眼电信号(EOG)的眨眼检测算法
- 一个前端报表设计器的设计分析
- TDM与FDM的比较
- 分治法查找数组元素的最大值和最小值(python实现)
- 知识蒸馏论文翻译(1)——CONFIDENCE-AWARE MULTI-TEACHER KNOWLEDGE DISTILLATION(多教师知识提炼)
- php性能优化的几个方法
- BZOJ1003 物流运输(dp+spfa)