天天看點

前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】【024】page-json配置【025】圖文、視訊和清單樣式(上)【026】圖文、視訊和清單樣式(下)【027】封裝清單樣式元件【028】滾動tab導航開發【029】滾動tab導航開發(下)【030】封裝滾動tab導航元件【031】上拉加載元件開發【032】封裝上拉加載元件【033】優化圖文清單元件【034】封裝無資料預設元件

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

文章目錄

  • 【024】page-json配置
  • 【025】圖文、視訊和清單樣式(上)
    • 圖檔引入
    • 設計細節
    • 整體代碼
  • 【026】圖文、視訊和清單樣式(下)
    • 設計細節
    • 整體代碼
  • 【027】封裝清單樣式元件
    • 資料存儲
    • 狀态(關注、贊、踩)辨別
    • 封裝元件
  • 【028】滾動tab導航開發
    • 操作步驟
    • 其他注意點
    • 整體代碼
  • 【029】滾動tab導航開發(下)
    • 注意點
    • 詳細代碼
  • 【030】封裝滾動tab導航元件
    • 步驟總結
    • 詳細代碼
  • 【031】上拉加載元件開發
    • 流程簡述
    • 核心代碼
    • 效果圖
  • 【032】封裝上拉加載元件
    • 流程簡述
    • 核心代碼
  • 【033】優化圖文清單元件
    • 具體優化
    • 元件代碼
  • 【034】封裝無資料預設元件
    • 具體優化
    • 核心代碼
    • 效果圖

【024】page-json配置

官方文檔 https://uniapp.dcloud.io/collocation/pages?id=配置項清單

官方文檔 https://uniapp.dcloud.io/collocation/pages?id=style

可以在page-json中配置一些樣式,包括“導航欄”、“按鈕”、“下拉重新整理”等樣式。

大多數内容可以到官方文檔中找到,下面給出一種配置的樣式

{
	"pages": [ //pages數組中第一項表示應用啟動頁,參考:https://uniapp.dcloud.io/collocation/pages
		{
			"path": "pages/index/index",
			"style": {
				// "navigationBarTitleText": "仿糗事百科"
             
				"app-plus": {
					// 隐藏滾動條
					"scrollIndicator":"none",
					// 配置導航欄
					"titleNView": {
						// 配置搜尋框
						"searchInput": {
							// 對齊方式(預設值center)
							"align": "center",
							// 背景色
							"backgroundColor": "#F7F7F7",
							// 邊框圓角
							"borderRadius": "4px",
							// 提示文字
							"placeholder": "搜尋糗事",
							// 阻止輸入(一般都是阻止輸入,點選後跳轉到搜尋頁面)
							"disabled": "true"
						},
						// 配置按鈕
						"buttons": [
							// 左邊按鈕
							{
								// 設定顔色
								"color": "#FF9619",
								// 設定按鈕按下的顔色
								"colorPressed": "#BBBBBB",
								// 設定浮動
								"float": "left",
								// 設定按鈕上文字大小
								"fontSize": "22px",
								// 設定字型檔案的路徑
								"fontSrc": "/static/font/icon.ttf",
								// 設定按鈕上顯示的文字
								"text": "\ue609"
							},
							// 右邊按鈕
							{
								"color": "#000000",
								"colorPressed": "#BBBBBB",
								"float": "right",
								"fontSize": "22px",
								"fontSrc": "/static/font/icon.ttf",
								"text": "\ue653"
							}
						]
					}
				}
			}
		}
        ,{
            "path" : "pages/news/news",
            "style" : {}
        }
        ,{
            "path" : "pages/paper/paper",
            "style" : {}
        }
        ,{
            "path" : "pages/home/home",
            "style" : {}
        }
    ],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "仿糗事百科",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	},
	"tabBar": {
		"color":"#adadad",         // 導航欄文字預設顔色
		"selectedColor":"#fee42a", // 導航欄選中顔色
		"backgroundColor":"#fff",  // 導航欄背景顔色
		"borderStyle":"white",     // 導航欄邊框樣式
		"list":[                   // tab的清單
			{
				"pagePath":"pages/index/index",                 // 導航欄對應頁面路徑(不用寫.vue)
				"text":"糗事",                                  // 導航欄文字
				"iconPath":"static/tabbar/index.png",           // 導航欄未選中的圖示路徑
				"selectedIconPath":"static/tabbar/indexed.png"  // 導航欄已選中的圖示路徑
			},
			{
				"pagePath":"pages/news/news",
				"text":"動态",
				"iconPath":"static/tabbar/news.png",
				"selectedIconPath":"static/tabbar/newsed.png"
			},
			{
				"pagePath":"pages/paper/paper",
				"text":"小紙條",
				"iconPath":"static/tabbar/paper.png",
				"selectedIconPath":"static/tabbar/papered.png"
			},
			{
				"pagePath":"pages/home/home",
				"text":"我的",
				"iconPath":"static/tabbar/home.png",
				"selectedIconPath":"static/tabbar/homed.png"
			}
		]
	}
}
           

注:

  • buttons

    中字型的路徑

    fontSrc

    對應了圖示項目中的iconfont.ttf檔案的路徑,一般将其引入到uni-app項目中的

    /static/font

    檔案夾下
  • buttons

    中提示文字

    text

    ,填寫的内容為圖示項目中demo_index.html打開後Unicode下,該圖示的編号。例如:某圖示在Unicode中編号為

    

    ,就應該填寫

    "text": "\ue601"

    ,以此類推。

【025】圖文、視訊和清單樣式(上)

圖檔引入

圖檔元件——官方文檔 https://uniapp.dcloud.io/component/image

格式大緻如下

屬性 功能

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

    u-f-ac

    u-f-ajc

    u-f-jsb

    這樣的類名,然後給需要的标簽加上這些類名。

整體代碼

  • index.css檔案
    <template>
    	<view>
    		<view class="index-list">
    			<view class="index-list1 u-f-ac u-f-jsb">
    				<view class="u-f-ac">
    					<image src="../../static/demo/userpic/12.jpg" mode="widthFix" lazy-load></image>
    					昵稱
    				</view>
    				<view class="u-f-ac">
    					<view class="icon iconfont icon-zengjia"></view>關注
    				</view>
    			</view>
    			<view class="index-list2">這是标題</view>
    			<view class="index-list3">
    				<image src="../../static/demo/datapic/11.jpg" mode="widthFix" lazy-load></image>
    			</view>
    			<view class="index-list4 u-f-ac u-f-jsb">
    				<view class="u-f-ac">
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-icon_xiaolian-mian u-f-ac"></view>
    						10
    					</view>
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-kulian u-f-ac"></view>
    						10
    					</view>
    				</view>
    				<view class="u-f-ac">
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-pinglun1 u-f-ac"></view>
    						10
    					</view>
    					<view class="u-f-ac">
    						<view class="icon iconfont icon-zhuanfa u-f-ac"></view>
    						10
    					</view>
    				</view>
    			</view>
    		</view>
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				title: 'Hello'
    			}
    		},
    		onLoad() {
    
    		},
    		methods: {
    
    		}
    	}
    </script>
    
    <style>
    	/* common.css在App.vue檔案中引入了進來 */
    	.index-list {
    		padding: 20upx;
    		border-bottom: 1upx solid #EEEEEE;
    	}
    	
    	.index-list1>view:first-child {
    		color: #999999;
    	}
    	
    	.index-list1>view:first-child image {
    		width: 90upx;
    		height: 90upx;
    		border-radius: 50%;
    		margin-right: 10upx;
    	}
    	
    	.index-list1>view:last-child {		
    		background-color: #F4F4F4;
    		border-radius: 5upx;
    		padding: 0 10upx;
    	}
    	
    	.index-list2 {
    		padding-top: 15upx;
    		font-size: 32upx;
    	}
    
    	.index-list3 {
    		padding-top: 15upx;
    	}
    
    	.index-list3>image {
    		width: 100%;
    		border-radius: 20upx;
    	}
    
    	.index-list4 {
    		padding: 15upx 0;
    	}
    	
    	.index-list4>view {
    		color: #999999;
    	}
    	
    	.index-list4>view>view:first-child, .index-list4>view>view>view {
    		margin-right: 10upx;
    	}
    </style>
               
  • common.css檔案
    /* 代表flex布局 */
    .u-f, .u-f-ac, .u-f-ajc, .u-f-jsb {
    	display: flex;
    }
    
    .u-f-ac, .u-f-ajc {
    	align-items: center;
    }
    
    .u-f-ajc {
    	justify-content: center;
    }
    
    .u-f-jsb {
    	justify-content: space-between;
    }
               
  • App.vue檔案
    <script>
    	export default {
    		onLaunch: function() {
    			console.log('App Launch')
    		},
    		onShow: function() {
    			console.log('App Show')
    		},
    		onHide: function() {
    			console.log('App Hide')
    		}
    	}
    </script>
    
    <style>
    	/*每個頁面公共css */
        @import './common/uni.css';
        @import './common/icon.css';
        @import './common/animate.css';
        @import './common/common.css';
    </style>
               
  • pages.json檔案

    和上一節一樣

  • 效果圖
    前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】【024】page-json配置【025】圖文、視訊和清單樣式(上)【026】圖文、視訊和清單樣式(下)【027】封裝清單樣式元件【028】滾動tab導航開發【029】滾動tab導航開發(下)【030】封裝滾動tab導航元件【031】上拉加載元件開發【032】封裝上拉加載元件【033】優化圖文清單元件【034】封裝無資料預設元件

【026】圖文、視訊和清單樣式(下)

設計細節

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

  1. 要讓某個元件顯示在另一個元件之上,可以把他們放到同一個父元件下,然後對父元件用

    postion: relative;

    ,對子元件用

    postion: absolute;

    。然後如果需要顯示在父元件的正中央,可以給父元件設定一個

    class="u-f-ajc"

    ;如果需要顯示在父元件的邊上,可以設定

    right

    left

    top

    bottom

    其中的不同方向上的兩個。
  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>
               
  • 其他檔案

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

  • 效果圖
    前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】【024】page-json配置【025】圖文、視訊和清單樣式(上)【026】圖文、視訊和清單樣式(下)【027】封裝清單樣式元件【028】滾動tab導航開發【029】滾動tab導航開發(下)【030】封裝滾動tab導航元件【031】上拉加載元件開發【032】封裝上拉加載元件【033】優化圖文清單元件【034】封裝無資料預設元件

【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

來辨別,值為

代表“未操作”,值為

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>
           

效果圖

前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】【024】page-json配置【025】圖文、視訊和清單樣式(上)【026】圖文、視訊和清單樣式(下)【027】封裝清單樣式元件【028】滾動tab導航開發【029】滾動tab導航開發(下)【030】封裝滾動tab導航元件【031】上拉加載元件開發【032】封裝上拉加載元件【033】優化圖文清單元件【034】封裝無資料預設元件

封裝元件

像是上面我們做好的一個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

    中,定義需要傳入的變量及其類型,像是這裡就需要将循環中的

    item

    index

    傳進來,形式為

    變量名: 類型

  5. 在index.vue檔案的

    script

    export default

    前,将元件檔案引入進來,形如:

    注:将中劃線命名改寫為小駝峰命名

  6. 在index.vue檔案的

    script

    components

    中,注冊相應的元件
  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-x

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

    scroll-view

    元件設定

    border-bottom

    屬性,調整導航欄分隔線的樣式
  • 可以對

    .swiper-tab-list

    的清單渲染

    view

    元件設定文字的樣式
  • 可以對

    .uni-tab-bar

    下的

    .active

    的清單渲染

    view

    元件設定被選中後的文字樣式
  • 如果要添加被選中後文字下方出現下劃線的樣式,可以在被清單渲染的

    view

    元件下再加一個

    class="swiper-tab-line"

    view

    元件,然後對

    .active

    下的

    .swiper-tab-line

    設定類似

    border-botom

    margin: 0 auto;

    border-radius

    等等樣式

整體代碼

以下僅展示index.vue檔案的代碼

<template>
	<view>
		<view class="uni-tab-bar">
			<scroll-view scroll-x class="uni-swiper-tab">
				<block v-for="(tab, index) in tabBars" :key="tab.id">
					<view class="swiper-tab-list" :class="{'active': tabIndex==index}" @tap="tabtap(index)">
						{{tab.name}}
						<view class="swiper-tab-line"></view>
					</view>
				</block>
			</scroll-view>
		</view>
		
		<!-- <block v-for="(item, index) in list" :key="index">
			<index-list :item="item" :index="index"></index-list>
		</block> -->
	</view>
</template>

<script>
	import indexList from "../../components/index/index-list.vue";
	export default {
		components: {
			indexList
		},
		data() {
			return {
				tabIndex: 0,
				tabBars: [
					{name: "關注", id: "guanzhu"},
					{name: "推薦", id: "tuijian"},
					{name: "體育", id: "tiyu"},
					{name: "熱點", id: "redian"},
					{name: "财經", id: "caijing"},
					{name: "娛樂", id: "yule"}
				],
				list:[
					{
						// 使用者頭像
						userpic: "../../static/demo/userpic/12.jpg",
						// 使用者名
						username: "昵稱",
						// 關注情況
						isguanzhu: false,
						// 标題
						title: "這是标題",
						// 類型(img-圖文,video-視訊)
						type: "img",
						// 封面圖
						titlepic: "../../static/demo/datapic/11.jpg",
						// 贊、踩數,标記情況
						infonum: {
							index: 1,  // 0-無操作,1-頂了,2-踩了
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
					{
						userpic: "../../static/demo/userpic/12.jpg",
						username: "昵稱",
						isguanzhu: true,
						title: "這是标題",
						type: "video",
						titlepic: "../../static/demo/datapic/11.jpg",
						// 播放次數
						playnum: "2w",
						long: "2:47",
						infonum: {
							index: 2,
							dingnum: 11,
							cainum: 11,
						},
						commentnum: 10,
						sharenum: 10
					},
				]
			}
		},
		onLoad() {

		},
		methods: {
			tabtap(index){
				this.tabIndex=index;
			}
		}
	}
</script>

<style>
	.swiper-tab-list {
		color: #969696;
		font-weight: bold;
	}
	
	.uni-swiper-tab {
		border-bottom: 1upx solid #EEEEEE;
	}
	
	.uni-tab-bar .active {
		color: #343434;
	}
	
	/* 被選中才出現下劃線 */
	.active .swiper-tab-line {
		border-bottom: 6upx solid #FEDE33;
		width: 70upx;
		margin: 0 auto;
		border-top: 6upx solid #FEDE33;
		border-radius: 20upx;
	}
</style>
           

效果圖

前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】【024】page-json配置【025】圖文、視訊和清單樣式(上)【026】圖文、視訊和清單樣式(下)【027】封裝清單樣式元件【028】滾動tab導航開發【029】滾動tab導航開發(下)【030】封裝滾動tab導航元件【031】上拉加載元件開發【032】封裝上拉加載元件【033】優化圖文清單元件【034】封裝無資料預設元件

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

    height

    被計算為

    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>
           

效果圖

前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】【024】page-json配置【025】圖文、視訊和清單樣式(上)【026】圖文、視訊和清單樣式(下)【027】封裝清單樣式元件【028】滾動tab導航開發【029】滾動tab導航開發(下)【030】封裝滾動tab導航元件【031】上拉加載元件開發【032】封裝上拉加載元件【033】優化圖文清單元件【034】封裝無資料預設元件

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

效果圖

前端開發~uni-app ·[項目-仿糗事百科] 學習筆記 ·008【首頁開發】【024】page-json配置【025】圖文、視訊和清單樣式(上)【026】圖文、視訊和清單樣式(下)【027】封裝清單樣式元件【028】滾動tab導航開發【029】滾動tab導航開發(下)【030】封裝滾動tab導航元件【031】上拉加載元件開發【032】封裝上拉加載元件【033】優化圖文清單元件【034】封裝無資料預設元件

繼續閱讀