前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】

注:前言、目錄見 https://god-excious.blog.csdn.net/article/details/105312456

【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 圖片懶加載

設計細節

在設計時,需要注意以下一些細節

  1. 首先按照設計圖,對某個區域可以分成若干行,我們把這些行都做成class="網頁名-list-i"view組件,然後將它們放到一個class="網頁名-list"view組件中
  2. 像是頭像、暱稱這一組,或者是**+icon、關注這一組,都是水平方向上垂直居中排列的,可以把文字(直接寫到父標籤下,不一定要新建標籤)、圖像放到一個view組件下,然後以flex佈局(默認主軸方向即可)設置交叉軸(縱向)居中——align-item: center;**,即可在同一行上垂直居中排版
  3. 像是贊數、踩數這一組,或者是評論數、轉發數這一組,水平方向上垂直居中和上面類似,還要設計好圖標與文字之間的間距,可以給圖標設置一個**margin-right,如果有多個圖標和文字的組,並且排列在同一側,可以給圖標的父標籤設置一個margin-right**,讓組與組之間保持間距。
  4. 設計圖中的一些圓角不要忽略了
  5. 行與行之間的間距可以通過給類名爲網頁名-list-i的元素設置一個padding-top,最後一個行元素可以考慮設置一個padding: ??px, 0;讓上下都保持一部分間距
  6. 整個區域內部的邊緣地區若有少量間距,可以對整個區域的標籤設置一個padding,顯示出這樣的空隙。
  7. 整個區域往下的分隔線,可以通過設置border-bottom屬性實現
  8. 阿里巴巴矢量圖庫項目的圖標引入,可以參考章節【010】
  9. 爲了增強CSS代碼複用性,可以把flex佈局的相關代碼提取出來,封裝到common.css文件裏去,一般根據flex佈局的樣式來起名,我們可以取出類似u-fu-f-acu-f-ajcu-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文件

    和上一節一樣

  • 效果圖

    1

【026】圖文、視頻和列表樣式(下)

設計細節

在設計時,有以下一些細節

  1. 要讓某個組件顯示在另一個組件之上,可以把他們放到同一個父組件下,然後對父組件用postion: relative;,對子組件用postion: absolute;。然後如果需要顯示在父組件的正中央,可以給父組件設置一個class="u-f-ajc";如果需要顯示在父組件的邊上,可以設置rightlefttopbottom其中的不同方向上的兩個。
  2. 如果需要調節帶透明的背景色,可以到Chrome瀏覽器中打開開發者工具,隨便找一個元素,添加屬性color,然後點擊對應的顏色,拖動透明度條,進行調節,如果需要rgba,點擊上下切換的小箭頭切換,然後把color屬性裏的rgba值複製過來。
  3. 對於阿里巴巴矢量圖標庫項目中,通過添加類名引入的圖標,如果要設置其大小,只需要設置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>
    
  • 其他文件

    和上一小節相同,不再重複

  • 效果圖

    2

【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>

效果圖

3

封裝組件

像是上面我們做好的一個list樣式,就可以封裝起來。

封裝的步驟如下:

  1. 創建好一個components文件夾,然後右鍵新建組件,在components文件夾下再創建一個index文件夾,把之前新建好的組件文件index-list.vue文件放到index文件夾

  2. index.vue文件block標籤下的所有標籤剪切,放到index-list.vue文件中對應位置

  3. index.vue文件style 下的所有樣式剪切,放到index-list.vue文件中對應位置。

    注:最好給裏面的style加上一個屬性scoped,避免在引入組件樣式後污染原本設置好的其他樣式

  4. index-list.vue文件script下的props中,定義需要傳入的變量及其類型,像是這裏就需要將循環中的itemindex傳進來,形式爲變量名: 類型

  5. index.vue文件scriptexport default前,將組件文件引入進來,形如:

    import indexList from "../../components/index/index-list.vue";
    

    注:將中劃線命名改寫爲小駝峯命名

  6. index.vue文件scriptcomponents中,註冊相應的組件

  7. 以標籤形式將組件進行引入,在屬性中傳入需要的參數,形如:

    <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文件,依次進行以下操作:

  1. uni-app-hello項目中的uni.css文件引入,方法可以參考【009】
  2. 將導航欄的文字內容以若干組{name: "??", id: "??"}的形式,寫到data中的數組tabBars下。
  3. 在外層創建一個class="uni-tab-bar"view組件
  4. 在上述view組件下創建一個class="uni-swiper-tab" scroll-xscroll-view組件
  5. 在上述scroll-view組件下創建一個block組件,屬性爲v-for="(tab,index) in tabBars" :key="tab.id",列表渲染class="swiper-tab-list"view組件
  6. 每一個被列表渲染的view組件內容顯示{{tab.name}}

其他注意點

有如下注意點:

  • 如果需要設置導航欄中當前選中項的樣式,可以對被列表渲染的view組件設置:class="{'active': tabIndex==index}"
  • 如果需要設置導航欄中某一項被點擊後成爲當前選中項,可以先在data中設置tabIndex值(先設置爲0代表初始選中第一個),然後在methods中設置一個處理函數tabtap(index),內容就是this.tabIndex=index;,最後放到被列表渲染的view組件上用@tap="tabtap(index)"綁定事件處理
  • 可以對.uni-swiper-tabscroll-view組件設置border-bottom屬性,調整導航欄分隔線的樣式
  • 可以對.swiper-tab-list的列表渲染view組件設置文字的樣式
  • 可以對.uni-tab-bar下的.active的列表渲染view組件設置被選中後的文字樣式
  • 如果要添加被選中後文字下方出現下劃線的樣式,可以在被列表渲染的view組件下再加一個class="swiper-tab-line"view組件,然後對.active下的.swiper-tab-line設置類似border-botommargin: 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>

效果圖

4

【029】滾動tab導航開發(下)

swiper組件·官方文檔 https://uniapp.dcloud.io/component/swiper

獲取系統信息·官方文檔 https://uniapp.dcloud.io/api/system/info

注意點

  1. 創建數組數據newslist,裏面是6個list對象,分別與滾動欄上的6個種類對應
  2. 爲了能夠讓能容橫向滾動,和上一節類似地在class="uni-tab-bar"view組件中使用了class="swiper-box"swiper組件,在swiper組件下用swiper-item組件對數組newslist進行列表渲染,然後在swiper-item組件下用scroll-view組件創建滾動條,滾動條內將之前的內容block組件放入,大致就完成了
  3. 爲了獲取運行的系統的相關信息(如:系統的屏幕尺寸、顯示尺寸……),可以在script下的onLoad()中用uni.getSystemInfo({ success:(res)=> { } })在函數體中用res.windowHeight獲取顯示高度(其他屬性見上面給出的官方文檔)
  4. 如果要調節自適應的大小,可以變量swiperheight存儲大小對應的px值,然後給swiper組件設置相應尺寸的style(因爲upx不支持在style中動態綁定)。swiperheight的計算應該放到onLoad()中的uni.getSystemInfo裏,然後把結果傳入這個變量值中。由於在uin.css文件中,.uni-tab-bar.swiper-boxheight被計算爲calc(100% - 100upx),我們可以用類似的方法,計算出this.swiperheight=res.windowHeight-uni.upx2px(100);,這樣的高度是差不多就是可以自適應的。
  5. swiper組件設置:current:"tabIndex";可以讓橫向滾動時,顯示出對應的列表內容。
  6. 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導航組件

步驟總結

步驟如下:

  1. 首先還是和以前一樣,在components文件夾下的index文件夾下,新建swiper-tab-head.vue文件,將導航欄部分代碼剪切過來,將樣式部分代碼剪切過來,將點擊處理的方法剪切過來,在swiper-tab-head.vue文件props中定義好要使用到的變量,在index.vue文件中用自定義的swiper-tab-head組件將導航欄引入,然後以:tabBars="tabBars" :tabIndex="tabIndex"的方式傳入相關變量
  2. 但是僅僅是上面這樣還不夠,因爲點擊事件的方法調用在子組件裏,沒有修改到父組件裏面的變量值,因此要在子組件裏將點擊事件的處理改成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】上拉加載組件開發

流程簡述

  1. swiper組件下的swiper-item組件下的scroll-view組件下增加一個view組件,用於上拉加載
  2. swiper組件下的swiper-item組件下的scroll-view組件的scrolltolower事件綁定一個自定義函數loadmore(index)
  3. loadmore函數中,先根據newslist[index].loadtext的內容判斷加載狀態,如果不是待加載狀態,就不進行加載
  4. 加載前將狀態調整至加載中,加載到的數據追加到newslist[index].list中,然後再把加載狀態調整至待加載
  5. 沒有更多數據的狀態以後再討論

核心代碼

<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>

效果圖

5

【032】封裝上拉加載組件

流程簡述

之前其實也描述過了封裝的一般流程 點這裏

這裏再來描述一下:

  1. components文件夾下新建common文件夾代表這個組件是多頁面通用的
  2. common文件夾下新建一個頁面(這裏就是load-more.vue
  3. 將要封裝的部分(這裏就是<view class="load-more">{{items.loadtext}}</view>),剪切粘貼到剛纔新建的頁面中
  4. 將對應的樣式(這裏就是.load-more的樣式)剪切粘貼到剛纔新建的頁面中
  5. 將剛剛剪切的組件中要用到的數據在props中註冊,然後再把組件中使用的變量換成相應的變量名
  6. 在原來的頁面中通過import 小駝峯名 from ".vue文件路徑"
  7. 在原來的頁面中通過commponents註冊相應的組件
  8. 在原來的頁面中原來的組件的位置,使用自定義的組件,如果要傳參數可以用:變量名="具體變量"的形式傳入

核心代碼

  • 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】優化圖文列表組件

具體優化

  1. 點擊【關注】之後將不再出現【關注】按鈕(個人感覺這個可以優化爲已關注,方便快速取關)
  2. 點擊【頂】、【踩】之後,相應的數據會進行修改,相關的狀態會進行調整
  3. 點擊【文章標題】、【文章圖片】之後,會跳轉到相應的詳情頁(這裏先寫一個接口,只打印一下提示,以後再做具體實現)

組件代碼

(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>
    

效果圖

6
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章