文章目錄
- 前言
- 一、圖文串列樣式開發
- 1.pages.json配置
- 2.頭像、昵稱和關注按鈕
- 3.標題和互動按鈕
- 4.封裝樣式組件
- 二、串列組件優化
- 1.全域分割線開發
- 2.影片特效
- 3.關注功能完善
- 4.頂踩功能
- 三、滾動選項卡開發
- 1.選項卡動態顯示
- 2.串列滑動實作
- 3.串列顯示和同步
- 4.上拉加載開發
- 5.封裝上拉加載組件
- 6.封裝無資料默認組件
- 總結
前言
本文主要介紹了首頁圖文串列和滾動選項卡的開發:
圖文串列的開發,包括頂部導航欄配置,圖文串列項(頭像、昵稱、關注按鈕、標題、標題封面圖、點贊、踩、評論和分享)等的開發;
串列組件優化,包括分割線的開發和封裝,影片特效實作,關注、頂踩功能的完善;
滾動選項卡開發,包括頂部選項卡開發、串列的同步顯示和滑動,上拉加載的開發和封裝,無資料組件開發等,
一、圖文串列樣式開發
1.pages.json配置
洗掉之前創建的demo頁面及其目錄,之前在配置pages.json時,"pages"中并未設定style,此時需要設定"app-plus",即配置編譯到 App 平臺時的特定樣式,
先下載發帖的圖示,演示如下:

解壓下載后的壓縮包并將其中的iconfont.ttf復制到專案目錄下的static目錄下,并作為首頁配置的app-plus>titleNView>buttons>fontSrc;
同時在我的專案頁面選擇Unicode,并復制發帖icon的代碼,例如,修改為uni-app支持的格式\ue668,作為app-plus>titleNView>buttons>text,
關于app-plus的說明可參考檔案https://uniapp.dcloud.io/collocation/pages?id=app-plus,
pages.json如下:
{
"pages": [ //pages陣列中第一項表示應用啟動頁,參考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"app-plus": {
// 導航欄配置
"titleNView": {
// 搜索框配置
"searchInput": {
"align":"center",
"backgroundColor":"#F5F4F2",
"borderRadius":"4px",
"disabled": true,
"placeholder": "搜索帖子",
"placeholderColor": "#6D6C67"
},
// 按鈕設定
"buttons": [
{
"color":"#333333",
"colorPressed":"#FD597C",
"float":"right",
"fontSize":"20px",
"fontSrc":"/static/iconfont.ttf",
"text": "\ue668"
}
]
}
}
}
}
,{
"path" : "pages/news/news",
"style" :
{
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
,{
"path" : "pages/msg/msg",
"style" :
{
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
,{
"path" : "pages/my/my",
"style" :
{
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "Community Dating",
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#FFFFFF"
},
"tabBar": {
"color":"#323232",
"selectedColor":"#ED6384",
"backgroundColor":"#FFFFFF",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"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/msg/msg",
"text": "訊息",
"iconPath": "static/tabbar/paper.png",
"selectedIconPath": "static/tabbar/papered.png"
},
{
"pagePath": "pages/my/my",
"text": "我的",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/homed.png"
}
]
}
}
顯示:

可以看到,定義出了搜索框和發帖按鈕,點擊按鈕會改變顏色,
2.頭像、昵稱和關注按鈕
uni-app 支持的通用 css 單位包括 px、rpx:
- px
即螢屏像素, - rpx
即回應式px,一種根據螢屏寬度自適應的動態單位,以750寬的螢屏為基準,750rpx恰好為螢屏寬度,
開發者可以通過設計稿基準寬度計算頁面元素 rpx 值,設計稿 1px 與框架樣式 1rpx 轉換公式為設計稿 1px / 設計稿基準寬度 = 框架樣式 1rpx / 750rpx,所以頁面元素寬度在 uni-app 中的寬度計算公式為750 * 元素在設計稿中的寬度 / 設計稿基準寬度,
更多可參考https://uniapp.dcloud.io/frame?id=尺寸單位,
index.vue頁面設定頭像顯示如下:
<template>
<view>
<image src="/static/img/userpic/12.jpg" style="width: 65rpx; height: 65rpx;"></image>
</view>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
顯示:

在不同尺寸的設備上,其大小會自動縮放,
如需直接使用樣式和素材等檔案,可以直接點擊加QQ群
963624318 ,在群檔案夾uni-app實戰之社區交友APP中下載即可,
先實作圖文串列的第一部分,即頭像、昵稱和關注按鈕,如下:
<template>
<view>
<!-- 串列樣式 -->
<view style="padding: 20rpx;">
<!-- 頭像、昵稱和關注按鈕 -->
<view style="display: flex; align-items: center; justify-content: space-between;">
<view style="display: flex; align-items: center;">
<!-- 頭像 -->
<image src="/static/img/userpic/12.jpg" mode="" style="width: 65rpx; height: 65rpx; border-radius: 100%; margin-right: 20rpx;" lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view style="font-size: 30rpx; line-height: 1.5;">Corley</view>
<text style="color: #9D9589; font-size: 25rpx; line-height: 1.5;">2021-01-24 上午11:20</text>
</view>
</view>
<!-- 按鈕 -->
<view style="width: 90rpx; height: 50rpx; display: flex; align-items: center; justify-content: center; border-radius: 5rpx; background-color: #FF4A6A; color: #FFFFFF;">
關注
</view>
</view>
<!-- 標題 -->
<view></view>
<!-- 圖片 -->
<view></view>
<!-- 圖示按鈕 -->
<view></view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
顯示:

顯然,實作了頭像、昵稱、發布日期和關注按鈕的展示,
3.標題和互動按鈕
現進一步實作串列項的第二部分,即發帖標題、點贊、評論和分享等,
先按照之前的方法在https://www.iconfont.cn/中添加點贊、踩、評論和分享的圖示,再將iconfont.css更新至common/icon.css中,
index.vue如下:
<template>
<view>
<!-- 串列樣式 -->
<view style="padding: 20rpx;">
<!-- 頭像、昵稱和關注按鈕 -->
<view style="display: flex; align-items: center; justify-content: space-between;">
<view style="display: flex; align-items: center;">
<!-- 頭像 -->
<image src="/static/img/userpic/12.jpg" mode="" style="width: 65rpx; height: 65rpx; border-radius: 100%; margin-right: 20rpx;"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view style="font-size: 30rpx; line-height: 1.5;">Corley</view>
<text style="color: #9D9589; font-size: 25rpx; line-height: 1.5;">2021-01-24 上午11:20</text>
</view>
</view>
<!-- 按鈕 -->
<view style="width: 90rpx; height: 50rpx; display: flex; align-items: center; justify-content: center; border-radius: 5rpx; background-color: #FF4A6A; color: #FFFFFF;">
關注
</view>
</view>
<!-- 標題 -->
<view style="font-size: 30rpx; margin: 10rpx 0;">
uni-app入門教程
</view>
<!-- 圖片 -->
<image src="/static/img/datapic/42.jpg" style="height: 350rpx; width: 100%; border-radius: 5rpx;"></image>
<!-- 圖示按鈕 -->
<view style="display: flex; align-items: center;">
<view style="flex: 1; display: flex; align-items: center; justify-content: center;">
<text class="iconfont icon-dianzan" style="margin-right: 20rpx;"></text>
<text>1</text>
</view>
<view style="flex: 1; display: flex; align-items: center; justify-content: center;">
<text class="iconfont icon-cai" style="margin-right: 20rpx;"></text>
<text>1</text>
</view>
<view style="flex: 1; display: flex; align-items: center; justify-content: center;">
<text class="iconfont icon-pinglun" style="margin-right: 20rpx;"></text>
<text>1</text>
</view>
<view style="flex: 1; display: flex; align-items: center; justify-content: center;">
<text class="iconfont icon-fenxiang" style="margin-right: 20rpx;"></text>
<text>1</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
顯示:

可以看到,已經實作了一個串列項的基本內容,
4.封裝樣式組件
雖然已經實作了串列,但是可以看到代碼很冗余、有大量CSS重復代碼,同時串列可以復用,也可以封裝成組件,來提高代碼的復用率,
先優化專案代碼,將CSS樣式提取到公共的CSS檔案中,
common下新建檔案base.css,保存公共樣式如下:
/* 內外邊距 */
.p-2 {
padding: 20rpx;
}
/* flex布局 */
.flex {
display: flex;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.flex-1 {
flex: 1;
}
/* 圓角 */
.rounded-circle {
border-radius: 100%;
}
.rounded {
border-radius: 8rpx;
}
/* margin */
.mr-2 {
margin-right: 20rpx;
}
.my-1 {
margin-top: 10rpx;
margin-bottom: 0rpx;
}
/* 字體 */
.font-md {
font-size: 35rpx;
}
.font {
font-size: 30rpx;
}
.font-sm {
font-size: 25rpx;
}
/* 文字顏色 */
.text-white {
color: #FFFFFF;
}
.text-light-muted {
color: #A9A5A0;
}
/* 寬度 */
/* #ifndef APP-PLUS-NVUE */
.w-100 {
width: 100%;
}
/* #endif */
base.css檔案不僅可以應用于該專案,也可以應用于其他uni-app專案,
common目錄下新建common.css保存本專案全域樣式,如下:
/* 本專案全域樣式 */
.bg-main {
background-color: #FF4A6A;
}
App.vue中匯入CSS檔案,如下:
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每個頁面公共css */
/* 官方CSS庫 */
@import url("./common/uni.css");
/* 自定義圖示庫 */
@import url("./common/icon.css");
/* 影片庫 */
@import url("./common/animate.css");
/* 自定義樣式庫 */
@import url("./common/base.css");
/* 全域樣式 */
@import url("./common/common.css");
</style>
index.vue簡化如下:
<template>
<view>
<!-- 串列樣式 -->
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" src="/static/img/userpic/12.jpg" mode="" style="width: 65rpx; height: 65rpx;"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">Corley</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">2021-01-24 上午11:20</text>
</view>
</view>
<!-- 按鈕 -->
<view class="flex align-center justify-center rounded bg-main text-white" style="width: 90rpx; height: 50rpx;">
關注
</view>
</view>
<!-- 標題 -->
<view class="font my-1">
uni-app入門教程
</view>
<!-- 圖片 -->
<image class="rounded w-100" src="/static/img/datapic/42.jpg" style="height: 350rpx;"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-dianzan mr-2"></text>
<text>1</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-cai mr-2"></text>
<text>1</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-pinglun mr-2"></text>
<text>1</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>1</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
顯然,此時代碼更加簡潔美觀,并且可以達到與之前同樣的效果,
現進一步實作將串列項封裝為組件,
首先替換資料、實作串列渲染,如下:
<template>
<view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列樣式 -->
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view class="flex align-center justify-center rounded bg-main text-white" style="width: 90rpx; height: 50rpx;">
{{item.isFollow?'已關注':'關注'}}
</view>
</view>
<!-- 標題 -->
<view class="font my-1">
{{item.title}}
</view>
<!-- 圖片 -->
<image class="rounded w-100" :src="item.titlepic" style="height: 350rpx;"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count}}</text>
</view>
</view>
</view>
</block>
</view>
</template>
<script>
export default {
data() {
return {
list: [
{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support",
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
顯示:

顯然,已經實作了串列渲染,
再實作封裝到組件,專案下新建components目錄,下新建common目錄,下建common-list.vue作為串列組件,如下:
<template>
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view class="flex align-center justify-center rounded bg-main text-white" style="width: 90rpx; height: 50rpx;">
{{item.isFollow?'已關注':'關注'}}
</view>
</view>
<!-- 標題 -->
<view class="font my-1">
{{item.title}}
</view>
<!-- 圖片 -->
<image class="rounded w-100" :src="item.titlepic" style="height: 350rpx;"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object,
index: Number
},
}
</script>
<style>
</style>
index.vue中匯入并使用組件即可,如下:
<template>
<view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index"></common-list>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [
{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support",
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
},
components: {
commonList
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
可以達到與之前相同的效果,
二、串列組件優化
1.全域分割線開發
全域分割線也是以組件的形式添加,
先在components/common下新建divider.vue如下:
<template>
<view style="height: 15rpx; background-color: #F5F5F4;"></view>
</template>
<script>
</script>
<style>
</style>
因為分割線可能在很多地方都會用到,所以可以添加到全域組件,main.js中添加如下:
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
// 引入全域組件
import divider from './components/common/divider.vue';
Vue.component('divider', divider)
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
index.vue中無需匯入、直接使用即可,如下:
<template>
<view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [
{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support",
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
},
components: {
commonList
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
顯示:

可以看到,有比較明顯的分割線效果,
2.影片特效
現在進一步給串列組件添加影片特效,
因為有的帖子沒有封面圖,因此需要v-if進行判斷,需要修改組件common-list.vue,如下:
<template>
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view class="flex align-center justify-center rounded bg-main text-white" style="width: 90rpx; height: 50rpx;">
{{item.isFollow?'已關注':'關注'}}
</view>
</view>
<!-- 標題 -->
<view class="font my-1">
{{item.title}}
</view>
<!-- 圖片 -->
<image v-if="item.titlepic" class="rounded w-100" :src="item.titlepic" style="height: 350rpx;"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object,
index: Number
},
}
</script>
<style>
</style>
index.vue增加測驗資料,如下:
<template>
<view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [
{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support",
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "support",
support_count: 2,
unsupport_count: 0
},
comment_count: 5,
share_count: 1
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
},
components: {
commonList
},
onLoad() {
},
methods: {
}
}
</script>
<style>
</style>
顯示:

可以看到,沒有封面圖片,也能正常顯示,
此時再實作點擊關注按鈕、添加影片特效,common-list.vue如下:
<template>
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view class="flex align-center justify-center rounded bg-main text-white animate__animated animate__faster" hover-class="animate__jello" style="width: 90rpx; height: 50rpx;">
{{item.isFollow?'已關注':'關注'}}
</view>
</view>
<!-- 標題 -->
<view class="font my-1">
{{item.title}}
</view>
<!-- 圖片 -->
<image v-if="item.titlepic" class="rounded w-100" :src="item.titlepic" style="height: 350rpx;"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count}}</text>
</view>
<view class="flex align-center justify-center flex-1">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object,
index: Number
},
}
</script>
<style>
</style>
顯示:

可以看到,點擊關注按鈕時,已實作了影片效果,
現進一步實作4個圖示的特效,如下:
<template>
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view class="flex align-center justify-center rounded bg-main text-white animate__animated animate__faster" hover-class="animate__jello" style="width: 90rpx; height: 50rpx;">
{{item.isFollow?'已關注':'關注'}}
</view>
</view>
<!-- 標題 -->
<view class="font my-1">
{{item.title}}
</view>
<!-- 圖片 -->
<image v-if="item.titlepic" class="rounded w-100" :src="item.titlepic" style="height: 350rpx;"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object,
index: Number
},
}
</script>
<style>
</style>
common.css如下:
/* 本專案全域樣式 */
/* 背景 */
.bg-main {
background-color: #FF4A6A;
}
/* 文本顏色 */
.text-main {
color: #FF4A6A;
}
顯示:

顯然,也實作了影片效果,
3.關注功能完善
common-list組件需要定義介面,點擊頭像可以進入個人空間,點擊關注按鈕可以真正進行關注操作,點擊點贊和踩實作資料更新,點擊評論、轉發、標題和圖片等跳轉到詳情頁,一般可以通過系結事件實作,
common-list.vue組件系結事件實作介面如下:
<template>
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;" @click="openSpace"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view class="flex align-center justify-center rounded bg-main text-white animate__animated animate__faster" hover-class="animate__jello" style="width: 90rpx; height: 50rpx;" @click="follow">
{{item.isFollow?'已關注':'關注'}}
</view>
</view>
<!-- 標題 -->
<view class="font my-1" @click="openDetail">
{{item.title}}
</view>
<!-- 圖片 -->
<image v-if="item.titlepic" class="rounded w-100" :src="item.titlepic" style="height: 350rpx;" @click="openDetail"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main" @click="doSupport('support')">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main" @click="doSupport('unsupport')">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main" @click="openDetail">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main" @click="openDetail">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object,
index: Number
},
methods: {
// 打開個人空間
openSpace(){
console.log('Space opened');
},
// 關注
follow(){
console.log('Followed');
},
// 進入詳情頁
openDetail(){
console.log('Detail opened');
},
// 頂踩操作
doSupport(type){
console.log(type)
}
}
}
</script>
<style>
</style>
顯示:

可以看到,已經模擬出了介面操作,
現進一步實作關注功能,如下:
<template>
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;" @click="openSpace"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view v-if="!item.isFollow" class="flex align-center justify-center rounded bg-main text-white animate__animated animate__faster"
hover-class="animate__jello" style="width: 90rpx; height: 50rpx;" @click="follow">
關注
</view>
</view>
<!-- 標題 -->
<view class="font my-1" @click="openDetail">
{{item.title}}
</view>
<!-- 圖片 -->
<image v-if="item.titlepic" class="rounded w-100" :src="item.titlepic" style="height: 350rpx;" @click="openDetail"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="doSupport('support')">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="doSupport('unsupport')">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="openDetail">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="openDetail">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object,
index: Number
},
methods: {
// 打開個人空間
openSpace() {
console.log('Space opened');
},
// 關注
follow() {
console.log('Followed');
// 通知父組件
this.$emit('follow', this.index);
},
// 進入詳情頁
openDetail() {
console.log('Detail opened');
},
// 頂踩操作
doSupport(type) {
console.log(type)
}
}
}
</script>
<style>
</style>
父組件index.vue如下:
<template>
<view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index" @follow="follow"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [
{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support",
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "support",
support_count: 2,
unsupport_count: 0
},
comment_count: 5,
share_count: 1
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
},
components: {
commonList
},
onLoad() {
},
methods: {
// 關注
follow(e){
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注'+this.list[e].username+'成功'
})
}
}
}
</script>
<style>
</style>
可以看到,實作了子組件common-list向父組件index的訊息傳遞,
顯示:

顯然,實作了正常的關注功能,
4.頂踩功能
現完善頂踩功能介面,
頂踩有3種狀態:頂、踩或未操作,點擊頂按鈕后,對應數值加1,并且顏色變為激活狀態,
common-list.vue如下:
<template>
<view class="p-2">
<!-- 頭像、昵稱和關注按鈕 -->
<view class="flex align-center justify-between">
<view class="flex align-center">
<!-- 頭像 -->
<image class="rounded-circle mr-2" :src="item.userpic" mode="" style="width: 65rpx; height: 65rpx;" @click="openSpace"
lazy-load></image>
<!-- 昵稱和發布時間 -->
<view>
<view class="font" style="line-height: 1.5;">{{item.username}}</view>
<text class="font-sm text-light-muted" style="line-height: 1.5;">{{item.newstime}}</text>
</view>
</view>
<!-- 按鈕 -->
<view v-if="!item.isFollow" class="flex align-center justify-center rounded bg-main text-white animate__animated animate__faster"
hover-class="animate__jello" style="width: 90rpx; height: 50rpx;" @click="follow">
關注
</view>
</view>
<!-- 標題 -->
<view class="font my-1" @click="openDetail">
{{item.title}}
</view>
<!-- 圖片 -->
<image v-if="item.titlepic" class="rounded w-100" :src="item.titlepic" style="height: 350rpx;" @click="openDetail"></image>
<!-- 圖示按鈕 -->
<view class="flex align-center">
<!-- 頂 -->
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="doSupport('support')" :class="item.support.type === 'support' ? 'support-active' : ''">
<text class="iconfont icon-dianzan mr-2"></text>
<text>{{item.support.support_count > 0 ? item.support.support_count : '支持'}}</text>
</view>
<!-- 踩 -->
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="doSupport('unsupport')" :class="item.support.type === 'unsupport' ? 'support-active' : ''">
<text class="iconfont icon-cai mr-2"></text>
<text>{{item.support.unsupport_count > 0 ? item.support.unsupport_count : '反對'}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="openDetail">
<text class="iconfont icon-pinglun mr-2"></text>
<text>{{item.comment_count > 0 ? item.comment_count : '評論'}}</text>
</view>
<view class="flex align-center justify-center flex-1 animate__animated animate__faster" hover-class="animate__jello text-main"
@click="openDetail">
<text class="iconfont icon-fenxiang mr-2"></text>
<text>{{item.share_count > 0 ? item.share_count : '分享'}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object,
index: Number
},
methods: {
// 打開個人空間
openSpace() {
console.log('Space opened');
},
// 關注
follow() {
console.log('Followed');
// 通知父組件
this.$emit('follow', this.index);
},
// 進入詳情頁
openDetail() {
console.log('Detail opened');
},
// 頂踩操作
doSupport(type) {
console.log(type);
// 通知父組件
this.$emit('doSupport', {
type,
index: this.index
})
}
}
}
</script>
<style>
.support-active {
color: #FF4A6A;
}
</style>
index.vue如下:
<template>
<view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
},
components: {
commonList
},
onLoad() {
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
}
}
}
</script>
<style>
</style>
在父組件和子組件中進行了一系列優化,包括圖示顏色變化,限制用戶要么為頂要么為踩、并且只能踩頂一次、不能多次踩頂,次數為0時顯示文本等,
顯示:

顯然,已經實作了頂踩的基本功能,
三、滾動選項卡開發
1.選項卡動態顯示
滾動選項卡采用scroll-view組件實作,其scroll-into-view屬性可以加速開發,
先實作滾動選項卡,base.css設定scroll-view樣式如下:
/* 內外邊距 */
.p-2 {
padding: 20rpx;
}
/* flex布局 */
.flex {
display: flex;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.flex-1 {
flex: 1;
}
/* 圓角 */
.rounded-circle {
border-radius: 100%;
}
.rounded {
border-radius: 8rpx;
}
/* margin */
.mr-2 {
margin-right: 20rpx;
}
.my-1 {
margin-top: 10rpx;
margin-bottom: 0rpx;
}
/* padding */
.px-5 {
padding-left: 50rpx;
padding-right: 50rpx;
}
.py-3 {
padding-top: 30rpx;
padding-bottom: 30rpx;
}
/* 字體 */
.font-md {
font-size: 35rpx;
}
.font {
font-size: 30rpx;
}
.font-sm {
font-size: 25rpx;
}
/* 文字顏色 */
.text-white {
color: #FFFFFF;
}
.text-light-muted {
color: #A9A5A0;
}
/* 寬度 */
/* #ifndef APP-PLUS-NVUE */
.w-100 {
width: 100%;
}
/* #endif */
/* scroll-view */
/* #ifndef APP-PLUS-NVUE */
.scroll-row {
width: 100%;
white-space: nowrap;
}
.scroll-row-item {
display: inline-block !important;
}
/* #endif */
index.vue中增加滾動選項卡如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row">
<view v-for="i in 20" :key="i" class="scroll-row-item px-5 py-3">{{i}}</view>
</scroll-view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
},
components: {
commonList
},
onLoad() {
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
}
}
}
</script>
<style>
</style>
顯示:

可以看到,已經實作了滾動,
現實作選項卡內容顯示,如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row ">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index" :class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''">{{item.name}}</view>
</scroll-view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
}
],
tabIndex: 0
}
},
components: {
commonList
},
onLoad() {
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
}
}
}
</script>
<style>
</style>
base.css如下:
/* 內外邊距 */
.p-2 {
padding: 20rpx;
}
/* flex布局 */
.flex {
display: flex;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.flex-1 {
flex: 1;
}
/* 圓角 */
.rounded-circle {
border-radius: 100%;
}
.rounded {
border-radius: 8rpx;
}
/* margin */
.mr-2 {
margin-right: 20rpx;
}
.my-1 {
margin-top: 10rpx;
margin-bottom: 0rpx;
}
/* padding */
.px-5 {
padding-left: 50rpx;
padding-right: 50rpx;
}
.px-3 {
padding-left: 30rpx;
padding-right: 30rpx;
}
.py-3 {
padding-top: 30rpx;
padding-bottom: 30rpx;
}
.py-2 {
padding-top: 20rpx;
padding-bottom: 20rpx;
}
/* 字體 */
.font-lg {
font-size: 40rpx;
}
.font-md {
font-size: 35rpx;
}
.font {
font-size: 30rpx;
}
.font-sm {
font-size: 25rpx;
}
.font-weight-bold {
font-weight: bold;
}
/* 文字顏色 */
.text-white {
color: #FFFFFF;
}
.text-light-muted {
color: #A9A5A0;
}
/* 寬度 */
/* #ifndef APP-PLUS-NVUE */
.w-100 {
width: 100%;
}
/* #endif */
/* scroll-view */
/* #ifndef APP-PLUS-NVUE */
.scroll-row {
width: 100%;
white-space: nowrap;
}
.scroll-row-item {
display: inline-block !important;
}
/* #endif */
顯示:

再系結事件實作動態滾動和影片顯示的效果,如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: ''
}
},
components: {
commonList
},
onLoad() {
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index){
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
}
}
}
</script>
<style>
</style>
顯示:

可以看到,已經實作了動態滑動,
2.串列滑動實作
現進一步實作點擊選項卡,下面顯示對應的串列,使用swiper(滑塊視圖容器)實作,可以做輪播圖和滑動串列,其常見屬性和含義如下:
| 屬性名 | 型別 | 默認值 | 含義 |
|---|---|---|---|
| indicator-dots | Boolean | false | 是否顯示面板指示點 |
| autoplay | Boolean | false | 是否自動切換 |
| current | Number | 0 | 當前所在滑塊的 index |
| interval | Number | 5000 | 自動切換時間間隔 |
| duration | Number | 500 | 滑動影片時長 |
具體可參考https://uniapp.dcloud.io/component/swiper,
先實作滑塊,并與上面的選項卡聯動,如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab">
<swiper-item v-for="(item, index) in tabBars" :key="index">
<view class="swiper-item">{{item.name}}</view>
</swiper-item>
</swiper>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: ''
}
},
components: {
commonList
},
onLoad() {
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index){
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
}
}
</script>
<style>
</style>
顯示:

可以看到,實作了滑塊,并且滑塊可以和選項卡實作聯動同步,
現實作滑塊串列示意,如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in tabBars" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
<view v-for="i in 100" :key="i">{{i}}</view>
</scroll-view>
</swiper-item>
</swiper>
<block v-for="(item, index) in list" :key="index">
<!-- 串列 -->
<common-list :item="item" :index="index" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList
},
onLoad() {
uni.getSystemInfo({
success:function(res){
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
})
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
}
}
}
</script>
<style>
</style>
為了給swiper設定高度,在生命周期onLoad()通過uni.getSystemInfo()獲取windowHeight,即可使用視窗高度,具體為螢屏高度除去NavigationBar和TabBar的高度,再減去選項卡的高度(呼叫uni.upx2px()轉化為以px為單位),
顯示:

可以看到,實作了串列滑動,
3.串列顯示和同步
現完善串列項,將之前實作的block放入swiper中,并根據頂部選項卡顯示不同的串列,
index.vue如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in newsList" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'">
<block v-for="(item2, index2) in item.list" :key="index2">
<!-- 串列 -->
<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
newsList: [],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList
},
onLoad() {
uni.getSystemInfo({
success: function(res) {
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
}),
// 根據選項生成串列
this.getData();
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
},
// 獲取資料
getData() {
var arr = [];
for (let i = 0; i < this.tabBars.length; i++) {
let obj = {
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
arr.push(obj)
}
this.newsList = arr;
}
}
}
</script>
<style>
</style>
顯示:

可以看到,已經實作了動態切換和顯示資料,
4.上拉加載開發
現實作上拉到底部加載資料,需要實作各個選項卡獨立上拉加載,
先實作基本的下拉加載,如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in newsList" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadMore(index)">
<!-- 串列 -->
<block v-for="(item2, index2) in item.list" :key="index2">
<!-- 串列組件 -->
<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
<!-- 上拉加載 -->
<view class="flex align-center justify-center py-3">
<text class="font text-light-muted">{{item.loadmore}}</text>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
newsList: [],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList
},
onLoad() {
uni.getSystemInfo({
success: function(res) {
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
}),
// 根據選項生成串列
this.getData();
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
},
// 獲取資料
getData() {
var arr = [];
for (let i = 0; i < this.tabBars.length; i++) {
// 生成串列模板
let obj = {
// 3種狀態:1.上拉加載更多;2.加載中...;3.沒有更多了,
loadmore: "上拉加載更多",
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
arr.push(obj)
}
this.newsList = arr;
},
// 上拉加載更多
loadMore(index) {
this.newsList[index].loadmore = '加載中...';
}
}
}
</script>
<style>
</style>
顯示:

可以看到,在下拉到底之前,訊息為上拉加載更多,到底后觸發@scrolltolower事件,變為加載中...,
再實作模擬加載更多資料,如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in newsList" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadMore(index)">
<!-- 串列 -->
<block v-for="(item2, index2) in item.list" :key="index2">
<!-- 串列組件 -->
<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
<!-- 上拉加載 -->
<view class="flex align-center justify-center py-3">
<text class="font text-light-muted">{{item.loadmore}}</text>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
newsList: [],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList
},
onLoad() {
uni.getSystemInfo({
success: function(res) {
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
}),
// 根據選項生成串列
this.getData();
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
},
// 獲取資料
getData() {
var arr = [];
for (let i = 0; i < this.tabBars.length; i++) {
// 生成串列模板
let obj = {
// 3種狀態:1.上拉加載更多;2.加載中...;3.沒有更多了,
loadmore: "上拉加載更多",
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
arr.push(obj)
}
this.newsList = arr;
},
// 上拉加載更多
loadMore(index) {
// 獲取當前串列
let item = this.newsList[index];
// 修改當前串列加載狀態
item.loadmore = '加載中...';
// 模擬資料請求
setTimeout(()=>{
// 加載資料
item.list = [...item.list, ...item.list];
// 恢復加載狀態
this.newsList[index].loadmore = '上拉加載更多';
}, 2000)
}
}
}
</script>
<style>
</style>
其中,[...item.list, ...item.list]是ES6的語法,為擴展運算子,即將item.list再復制一份;
之所以可以通過操作item變數來操作資料,是因為指向了相同的地址,即同一個參考,
顯示:

可以看到,模擬出了加載更多資料,
5.封裝上拉加載組件
前面實作的上拉加載更多并沒有進行判斷,可以一直向下滑動加載更多,顯然這是不合理的,因此需要進行判斷,
index.vue如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in newsList" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadMore(index)">
<!-- 串列 -->
<block v-for="(item2, index2) in item.list" :key="index2">
<!-- 串列組件 -->
<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
<!-- 上拉加載 -->
<view class="flex align-center justify-center py-3">
<text class="font text-light-muted">{{item.loadmore}}</text>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
export default {
data() {
return {
newsList: [],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList
},
onLoad() {
uni.getSystemInfo({
success: function(res) {
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
}),
// 根據選項生成串列
this.getData();
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
},
// 獲取資料
getData() {
var arr = [];
for (let i = 0; i < this.tabBars.length; i++) {
// 生成串列模板
let obj = {
// 3種狀態:1.上拉加載更多;2.加載中...;3.沒有更多了,
loadmore: "上拉加載更多",
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
arr.push(obj)
}
this.newsList = arr;
},
// 上拉加載更多
loadMore(index) {
// 獲取當前串列
let item = this.newsList[index];
// 判斷是否處于可加載狀態
if (item.loadmore !== '上拉加載更多') return;
// 修改當前串列加載狀態
item.loadmore = '加載中...';
// 模擬資料請求
setTimeout(()=>{
// 加載資料
item.list = [...item.list, ...item.list];
// 恢復加載狀態
this.newsList[index].loadmore = '上拉加載更多';
}, 2000)
}
}
}
</script>
<style>
</style>
效果與之前相同,如果loadmore不為上拉加載更多,則會停止加載更多資料,
現將下拉加載更多封裝為組件,components/common下新建load-more.vue如下:
<template>
<view class="flex align-center justify-center py-3">
<text class="font text-light-muted">{{loadmore}}</text>
</view>
</template>
<script>
export default {
props: ['loadmore']
}
</script>
<style>
</style>
index.vue中使用組件如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in newsList" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadMore(index)">
<!-- 串列 -->
<block v-for="(item2, index2) in item.list" :key="index2">
<!-- 串列組件 -->
<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
<!-- 上拉加載 -->
<load-more :loadmore="item.loadmore"></load-more>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import commonList from '@/components/common/common-list.vue';
import loadMore from '@/components/common/load-more.vue';
export default {
data() {
return {
newsList: [],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList,
loadMore
},
onLoad() {
uni.getSystemInfo({
success: function(res) {
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
}),
// 根據選項生成串列
this.getData();
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
},
// 獲取資料
getData() {
var arr = [];
for (let i = 0; i < this.tabBars.length; i++) {
// 生成串列模板
let obj = {
// 3種狀態:1.上拉加載更多;2.加載中...;3.沒有更多了,
loadmore: "上拉加載更多",
list: [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
]
}
arr.push(obj)
}
this.newsList = arr;
},
// 上拉加載更多
loadMore(index) {
// 獲取當前串列
let item = this.newsList[index];
// 判斷是否處于可加載狀態
if (item.loadmore !== '上拉加載更多') return;
// 修改當前串列加載狀態
item.loadmore = '加載中...';
// 模擬資料請求
setTimeout(()=>{
// 加載資料
item.list = [...item.list, ...item.list];
// 恢復加載狀態
this.newsList[index].loadmore = '上拉加載更多';
}, 2000)
}
}
}
</script>
<style>
</style>
效果與之前相同,
6.封裝無資料默認組件
先實作沒有資料的情況,如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in newsList" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadMore(index)">
<!-- 有資料 -->
<template v-if="item.list.length > 0">
<!-- 串列 -->
<block v-for="(item2, index2) in item.list" :key="index2">
<!-- 串列組件 -->
<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
<!-- 上拉加載 -->
<load-more :loadmore="item.loadmore"></load-more>
</template>
<!-- 無資料 -->
<template v-else>
<view class="flex flex-column align-center justify-center pt-7">
<image src="@/static/common/nothing.jpg" style="width: 300rpx; height: 300rpx;"></image>
<text class="font-md">這里什么都沒有哦~</text>
</view>
</template>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
const test_data = [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
];
import commonList from '@/components/common/common-list.vue';
import loadMore from '@/components/common/load-more.vue';
export default {
data() {
return {
newsList: [],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList,
loadMore
},
onLoad() {
uni.getSystemInfo({
success: function(res) {
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
}),
// 根據選項生成串列
this.getData();
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
},
// 獲取資料
getData() {
var arr = [];
for (let i = 0; i < this.tabBars.length; i++) {
// 生成串列模板
let obj = {
// 3種狀態:1.上拉加載更多;2.加載中...;3.沒有更多了,
loadmore: "上拉加載更多",
list: []
}
if (i % 3 !== 2) {
obj.list = test_data;
}
arr.push(obj)
}
this.newsList = arr;
},
// 上拉加載更多
loadMore(index) {
// 獲取當前串列
let item = this.newsList[index];
// 判斷是否處于可加載狀態
if (item.loadmore !== '上拉加載更多') return;
// 修改當前串列加載狀態
item.loadmore = '加載中...';
// 模擬資料請求
setTimeout(() => {
// 加載資料
item.list = [...item.list, ...item.list];
// 恢復加載狀態
this.newsList[index].loadmore = '上拉加載更多';
}, 2000)
}
}
}
</script>
<style>
</style>
base.css定義樣式如下:
/* 內外邊距 */
.p-2 {
padding: 20rpx;
}
/* flex布局 */
.flex {
display: flex;
}
.flex-column {
flex-direction: column;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.flex-1 {
flex: 1;
}
/* 圓角 */
.rounded-circle {
border-radius: 100%;
}
.rounded {
border-radius: 8rpx;
}
/* margin */
.mr-2 {
margin-right: 20rpx;
}
.my-1 {
margin-top: 10rpx;
margin-bottom: 0rpx;
}
/* padding */
.px-5 {
padding-left: 50rpx;
padding-right: 50rpx;
}
.px-3 {
padding-left: 30rpx;
padding-right: 30rpx;
}
.py-3 {
padding-top: 30rpx;
padding-bottom: 30rpx;
}
.py-2 {
padding-top: 20rpx;
padding-bottom: 20rpx;
}
.pt-7 {
padding-top: 70rpx;
}
/* 字體 */
.font-lg {
font-size: 40rpx;
}
.font-md {
font-size: 35rpx;
}
.font {
font-size: 30rpx;
}
.font-sm {
font-size: 25rpx;
}
.font-weight-bold {
font-weight: bold;
}
/* 文字顏色 */
.text-white {
color: #FFFFFF;
}
.text-light-muted {
color: #A9A5A0;
}
/* 寬度 */
/* #ifndef APP-PLUS-NVUE */
.w-100 {
width: 100%;
}
/* #endif */
/* scroll-view */
/* #ifndef APP-PLUS-NVUE */
.scroll-row {
width: 100%;
white-space: nowrap;
}
.scroll-row-item {
display: inline-block !important;
}
/* #endif */
顯示:

可以看到,部分頁面沒有資料,顯示的是圖片和提示文字,
再實作封裝為組件,components/common下新建no-thing.vue如下:
<template>
<view class="flex flex-column align-center justify-center pt-7">
<image src="@/static/common/nothing.jpg" style="width: 300rpx; height: 300rpx;"></image>
<text class="font-md">這里什么都沒有哦~</text>
</view>
</template>
<script>
</script>
<style>
</style>
main.js中引入全域組件如下:
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
// 引入全域組件
import divider from './components/common/divider.vue';
Vue.component('divider', divider)
import noThing from './components/common/no-thing.vue';
Vue.component('no-thing', noThing)
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
index.vue中使用全域組件如下:
<template>
<view>
<!-- 頂部選項卡 -->
<scroll-view scroll-x="true" class="scroll-row" :scroll-into-view="scrollInto" :scroll-with-animation="true" style="height: 100rpx;">
<view v-for="(item, index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md" :id="'tab'+index"
:class="tabIndex === index ? 'text-main font-lg font-weight-bold' : ''" @click="changeTab(index)">{{item.name}}</view>
</scroll-view>
<!-- 滑塊 -->
<swiper :duration="150" :current="tabIndex" @change="onChangeTab" :style="'height: '+scrollH+'px;'">
<swiper-item v-for="(item, index) in newsList" :key="index">
<scroll-view scroll-y="true" :style="'height: '+scrollH+'px;'" @scrolltolower="loadMore(index)">
<!-- 有資料 -->
<template v-if="item.list.length > 0">
<!-- 串列 -->
<block v-for="(item2, index2) in item.list" :key="index2">
<!-- 串列組件 -->
<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
<!-- 全域分割線 -->
<divider></divider>
</block>
<!-- 上拉加載 -->
<load-more :loadmore="item.loadmore"></load-more>
</template>
<!-- 無資料 -->
<template v-else>
<no-thing></no-thing>
</template>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
const test_data = [{
username: "Corley",
userpic: "/static/img/userpic/12.jpg",
newstime: "2021-01-24 上午11:30",
isFollow: false,
title: "uni-app入門教程",
titlepic: "/static/img/datapic/42.jpg",
support: {
type: "support", // 頂
support_count: 1,
unsupport_count: 2
},
comment_count: 2,
share_count: 2
},
{
username: "Brittany",
userpic: "/static/img/userpic/16.jpg",
newstime: "2021-01-24 下午14:00",
isFollow: false,
title: "商業資料分析從入門到入職",
support: {
type: "unsupport", // 踩
support_count: 2,
unsupport_count: 3
},
comment_count: 5,
share_count: 1
},
{
username: "Jessica",
userpic: "/static/img/userpic/7.jpg",
newstime: "2021-01-24 下午14:44",
isFollow: true,
title: "Django+Vue開發生鮮電商平臺",
titlepic: "/static/img/datapic/11.jpg",
support: {
type: "", // 未操作
support_count: 2,
unsupport_count: 7
},
comment_count: 0,
share_count: 2
},
{
username: "Ashley",
userpic: "/static/img/userpic/20.jpg",
newstime: "2021-01-24 下午18:20",
isFollow: true,
title: "uni-app實戰之社區交友APP",
titlepic: "/static/img/datapic/30.jpg",
support: {
type: "support",
support_count: 5,
unsupport_count: 1
},
comment_count: 3,
share_count: 0
}
];
import commonList from '@/components/common/common-list.vue';
import loadMore from '@/components/common/load-more.vue';
export default {
data() {
return {
newsList: [],
// 頂部選項卡
tabBars: [{
name: '關注'
},
{
name: '推薦'
},
{
name: '體育'
},
{
name: '熱點'
},
{
name: '財經'
},
{
name: '娛樂'
},
{
name: '軍事'
},
{
name: '歷史'
},
{
name: '本地'
}
],
tabIndex: 0,
scrollInto: '',
// 串列高度
scrollH: 600
}
},
components: {
commonList,
loadMore
},
onLoad() {
uni.getSystemInfo({
success: function(res) {
console.log(res);
this.scrollH = res.windowHeight - uni.upx2px(100);
}
}),
// 根據選項生成串列
this.getData();
},
methods: {
// 關注
follow(e) {
console.log('Index followed');
console.log(e);
this.list[e].isFollow = true;
uni.showToast({
title: '關注' + this.list[e].username + '成功'
})
},
// 頂踩操作
doSupport(e) {
console.log(e);
// 獲取當前串列項
let item = this.list[e.index];
let msg = e.type === 'support' ? '頂' : '踩';
// 之前未頂踩過
if (item.support.type === '') {
item.support[e.type + '_count']++;
}
// 之前已頂過并且現在的操作為踩,則頂-1、踩+1
else if (item.support.type === 'support' && e.type === 'unsupport') {
item.support.support_count--;
item.support.unsupport_count++;
}
// 之前已踩過并且現在的操作為頂,則踩-1、頂+1
else if (item.support.type === 'unsupport' && e.type === 'support') {
item.support.unsupport_count--;
item.support.support_count++;
}
item.support.type = e.type;
uni.showToast({
title: msg + '成功'
})
},
// 切換選項
changeTab(index) {
if (this.tabIndex === index) {
return;
}
this.tabIndex = index;
// 滾動到指定元素
this.scrollInto = 'tab' + index;
},
// 監聽滑動
onChangeTab(e) {
console.log(e);
this.changeTab(e.detail.current);
},
// 獲取資料
getData() {
var arr = [];
for (let i = 0; i < this.tabBars.length; i++) {
// 生成串列模板
let obj = {
// 3種狀態:1.上拉加載更多;2.加載中...;3.沒有更多了,
loadmore: "上拉加載更多",
list: []
}
if (i % 3 !== 2) {
obj.list = test_data;
}
arr.push(obj)
}
this.newsList = arr;
},
// 上拉加載更多
loadMore(index) {
// 獲取當前串列
let item = this.newsList[index];
// 判斷是否處于可加載狀態
if (item.loadmore !== '上拉加載更多') return;
// 修改當前串列加載狀態
item.loadmore = '加載中...';
// 模擬資料請求
setTimeout(() => {
// 加載資料
item.list = [...item.list, ...item.list];
// 恢復加載狀態
this.newsList[index].loadmore = '上拉加載更多';
}, 2000)
}
}
}
</script>
<style>
</style>
效果與之前相同,
總結
首頁的開發標志著進入正式的開發階段,代碼量逐漸增多、邏輯也逐漸復雜,圖文串列和滾動選項卡的開發業務邏輯較多,因此也進行了大量的優化,包括組件封裝和CSS樣式提取等,這都有利于專案的維護和擴展,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/253112.html
標籤:其他

963624318 ,在群檔案夾uni-app實戰之社區交友APP中下載即可,