31 uni-app前端后端交互剩余主體業務邏輯相關筆記


31 前端后端剩余粗糙筆記

一 綁定郵箱

image-20200507210002049

<template>
	<view>
		<!-- 修改郵箱沒有做細節處理 -->
		<input class="uni-input" type="text" v-model="email" placeholder="請輸入你要綁定的郵箱" :disabled="this.user.email"/>
		<view class="py-2 px-3">
			<button class="bg-main text-white" style="border-radius: 50rpx;border: 0;" type="primary" :disabled="disabled || this.user.email" :class="disabled ? 'bg-main-disabled' : ''" @click="submit">綁定</button>
		</view>
	</view>
</template>

<script>
	import {mapState} from 'vuex';
	export default {
		data() {
			return {
				email:""
			}
		},
		computed: {
			...mapState({
				user:state=>state.user
			}),
			disabled() {
				return this.email === ''
			}
		},
		onLoad() {
			if(this.user.email){
				this.email = this.user.email
			}
		},
		methods: {
			check(){
				let rule = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
				if (!rule.test(this.email)) {
					uni.showToast({
						title:"郵箱格式不正確",
						icon:"none"
					})
					return false;
				}
				return true
			},
			submit(){
				if (!this.check()) {
					return;
				}
				this.$H.post('/user/bindemail',{
					email:this.email
				},{
					token:true
				}).then(res=>{
					this.$store.commit('editUserInfo',{
						key:'email',
						value:this.email
					})
					uni.navigateBack({
						delta: 1
					});
					uni.showToast({
						title: '綁定郵箱成功',
						icon: 'none'
					});
				})
			}
		}
	}
</script>

<style>

</style>

二 綁定第三方數據(業務邏輯參考意義)

思路

如果該頁面涉及多個后端接口,

可以考慮把初始化數據設置為一個__init()方法,

修改完了很多數據后可以重新調用__init()方法。

效果圖:

image-20200507212346887

代碼:

<template>
	<view>
		<uni-list-item :title="item.name" 
		v-for="(item,index) in list"
		:key="index" @click="handleEvent(item)">
			<view class="flex align-center text-right text-light-muted" 
			slot="right_content">
				{{item.data}}
			</view>
		</uni-list-item>
	</view>
</template>

<script>
	import uniListItem from '@/components/uni-ui/uni-list-item/uni-list-item.vue';
	import { mapState } from 'vuex'
	export default {
		components: {
			uniListItem
		},
		data() {
			return {
				list:[]
			}
		},
		computed: {
			...mapState({
				user:state=>state.user
			})
		},
		onShow() {
			this.__init()
		},
		methods: {
			// 封裝為一個方法很有意義
			__init(){
				let list = [{
					name:"手機號",
					data:this.user.phone ? this.user.phone : "未綁定",
					type:"navigateTo",
					url:"/pages/user-phone/user-phone"
				},{ 
					name:"登錄密碼",
					data:this.user.password ? "修改密碼" : "未設置",
					type:"navigateTo",
					url:"/pages/user-password/user-password"
				},{ 
					name:"郵箱綁定",
					data:this.user.email ? this.user.email : "未綁定",
					type:"navigateTo",
					url:"/pages/user-email/user-email"
				}]
				this.list = [...list]
				this.$H.get('/user/getuserbind',{},{
					token:true
				}).then(res=>{
					this.$store.commit('editUserInfo',{
						key:"user_bind",
						value:res
					})
					let other = [{
						name:"微信賬號",
						data:this.user.user_bind.weixin ? this.user.user_bind.weixin.nickname:"未綁定",
						type:"bind",
						provider:"weixin"
					},{
						name:"微博賬號",
						data:this.user.user_bind.sinaweibo ? this.user.user_bind.sinaweibo.nickname:"未綁定",
						type:"bind",
						provider:"sinaweibo"
					},{
						name:"QQ賬號",
						data:this.user.user_bind.qq ? this.user.user_bind.qq.nickname:"未綁定",
						type:"bind",
						provider:"qq"
					}]
					this.list = [...this.list,...other]
				})
			},
			handleEvent(item){
				if(item.type === '') return
				switch (item.type){
					case 'navigateTo':
					uni.navigateTo({
						url: item.url,
					});
						break;
					case 'bind':
					if(item.data !== '未綁定'){
						return uni.showToast({
							title: '你已經綁定過了',
							icon: 'none'
						});
					}
					this.bind(item.provider)
						break;
				}
			},
			// 綁定第三方登錄
			bind(provider){
				uni.login({
					provider: provider,
					success: r => {
						uni.getUserInfo({
							provider: provider,
							success:(res)=> {
								let obj = {
									provider:provider,
									openid:res.userInfo.openId,
									nickName:res.userInfo.nickName,
									avatarUrl:res.userInfo.avatarUrl,
								}
								this.$H.post('/user/bindother',obj,{
									token:true,
									native:true
								}).then(result=>{
									if(result.data.errorCode){
										return uni.showToast({
											title: result.data.msg,
											icon: 'none'
										});
									}
									// 完成了操作后可以再次初始化數據。
									// 初次加載頁面需要初始化數據。
									// 完成了操作后可以根據后端數據再次初始化數據。(當然了也可以手動初始化前端數據,不過再走一便后端數據可以確定后端已經修改上了)
									this.__init()
									uni.showToast({
										title: '綁定成功',
										icon: 'none'
									});
								})
							}
						});
					},
				});
				
			}
		}
	}
</script>

<style>

</style>

三 修改頭像接口(封裝uni提供的上傳圖片請求)

image-20200508121406566

思路:

1 首先使用uni.chooseimage選擇圖片

2 使用自己封裝的上傳圖片ajax,注意最后這個ajax返回的是promise對象,這樣使用起來更方便(優秀)。

3 然后給index.js 更新一下user數據,然后存儲到前端本地。

涉及的核心代碼

Request.js

upload(url,options = {}){
		options.url = $C.webUrl + url
		options.header = options.header || {}
		// 驗證權限token
		if(options.token){
			options.header.token = $store.state.token
			if(!options.header.token){
				return uni.showToast({
					title: '非法token,請重新登錄',
					icon: 'none'
				});
			}
		}
		console.log(options)
		return new Promise((res,rej)=>{
			uni.uploadFile({
				...options,
				success: (uploadFileRes) => {
					console.log(uploadFileRes);
					if(uploadFileRes.statusCode !== 200){
						return uni.showToast({
							title: '上傳圖片失敗',
							icon: 'none'
						});
					}
					let data = JSON.parse(uploadFileRes.data)
					res(data)
				},
				fail:(err)=>{
					rej(err)
				}
			});
		})
		
	}
	
}

User-userinfo.vue

methods: {
			changeUserpic(){
				// 拍照或者選擇本地圖片
				uni.chooseImage({
					count:1,
					sizeType:["compressed"],
					sourceType:["album","camera"],
					success: (res) => {
						this.$H.upload('/edituserpic',{
							filePath: res.tempFilePaths[0],
							name: 'userpic',
							token:true
						}).then(result=>{
							console.log('###',result);
							this.$store.commit('editUserInfo',{
								key:"userpic",
								value:result.data
							})
							uni.showToast({
								title: '修改頭像成功',
								icon: 'none'
							});
						}).catch(err=>{
							console.log(err);
						})
						
					}
				})
			},

四 修改資料功能實現(日期框,三級聯動地址)

效果圖:

image-20200508154510681

關鍵點:

用了日期選框(調用系統原生的日期選擇器,並不友好)

用了一個開源的三級聯動(還ok吧)

代碼

<template>
	<view>
		<uni-list-item title="頭像" @click="changeUserpic">
			<!-- 為uni-list-item增加了插槽 -->
			<view class="flex align-center" slot="right_content">
				<image :src="user.userpic ? user.userpic : '/static/default.jpg' " class="rounded-circle" style="width: 100rpx; height: 100rpx;" mode=""></image>
				<text class="iconfont icon-bianji1 ml-2"></text>
			</view>
		</uni-list-item>
		<uni-list-item title="昵稱" @click="changeUsername">
			<view class="flex align-center w-100" slot="right_content">
				<input ref="usernameInput" class="text-right" type="text " value="" v-model="username" />
				<text class="iconfont icon-bianji1 ml-2"></text>
			</view>
		</uni-list-item>
		<uni-list-item title="性別" @click="changeSex">
			<view class="flex align-center" slot="right_content" >
				<text class="font">{{this.sexText}}</text>
				<text class="iconfont icon-bianji1 ml-2"></text>
			</view>
		</uni-list-item>
		
		<!-- picker日期表單,不用導入調用的是各個平台的原生日期渲染,如果能用自己的日期選擇器會更好。 -->
		<picker mode="date" :value="birthday" :start="startDate" :end="endDate" @change="onDateChange">
			<uni-list-item title="生日">
				<view class="flex align-center" slot="right_content">
					<text>{{birthday}}</text>
					<text class="iconfont icon-bianji1 ml-2"></text>
				</view>
			</uni-list-item>
		</picker>
			
			
		<!-- <picker mode="date" :value="birthday" :start="startDate" :end="endDate" @change="bindDateChange">
		                        <view class="uni-input">{{birthday}}</view>
		</picker> -->
			
			
		<uni-list-item title="情感 " @click='changeEmotion'>
			<view class="flex align-center" slot="right_content">
				<text>{{this.emotionText}}</text>
				<text class="iconfont icon-bianji1 ml-2"></text>
			</view>
		</uni-list-item>
		<uni-list-item title="職業" @click="changeJob">
			<view class="flex align-center" slot="right_content">
				<text>{{job}}</text>
				<text class="iconfont icon-bianji1 ml-2"></text>
			</view>
		</uni-list-item>
		<uni-list-item title="家鄉" @tap="openAddres2">
			<view class="flex align-center" slot="right_content">
				<text>{{address}}</text>
				<text class="iconfont icon-bianji1 ml-2"></text>
			</view>
		</uni-list-item>
		<view class="py-2 px-3">
			<button class="bg-main text-white" style="border-radius: 50rpx;border: 0;" type="primary" @click="submit">完成</button>
		</view>
		
		<simple-address ref="simpleAddress" :pickerValueDefault="cityPickerValueDefault" @onConfirm="onConfirm" themeColor="#007AFF"></simple-address>
	</view>
</template>

<script>
	const sexArray = ['保密','男','女']
	const jobArray = ['農民','it','教師']
	const emotionArray = ['保密', '未婚', '已婚']
	import uniListItem from '@/components/uni-ui/uni-list-item/uni-list-item.vue'
	import simpleAddress from '@/components/other-author-tools/simple-address/simple-address.nvue'
	
	import { mapState } from 'vuex'
	export default {
		components:{
			uniListItem,
			simpleAddress
			
		},
		data() {
			return {
				username:"昵稱",
				sex:0,
				emotion:0,
				job:"保密",
				birthday:"2019-01-01",
				startDate:"1900-01-01",
				endDate:"2100-01-01",
				cityPickerValueDefault: [0, 0, 1],
				address: '河南省-鄭州市-中原區'
			}
		},
		computed:{
			...mapState({
				user:state=>state.user
			}),
			sexText(){
				return sexArray[this.sex]
			},
			emotionText(){
				return emotionArray[this.emotion]
			},
			
			
		},
		onLoad() {
			let userinfo = this.user.userinfo
			if(userinfo){
				this.address = userinfo.path
				this.username = this.user.username
				this.sex =  userinfo.sex
				this.emotion = userinfo.qg
				this.job  = userinfo.job
				this.birthday  = userinfo.birthday
			}
			console.log(userinfo)
		},
		methods: {
			changeUserpic(){
				// 拍照或者選擇本地圖片
				uni.chooseImage({
					count:1,
					sizeType:["compressed"],
					sourceType:["album","camera"],
					success: (res) => {
						this.$H.upload('/edituserpic',{
							filePath: res.tempFilePaths[0],
							name: 'userpic',
							token:true
						}).then(result=>{
							console.log('###',result);
							this.$store.commit('editUserInfo',{
								key:"userpic",
								value:result.data
							})
							uni.showToast({
								title: '修改頭像成功',
								icon: 'none'
							});
						}).catch(err=>{
							console.log(err);
						})
						
					}
				})
			},
			// 修改昵稱 不用理會
			changeUsername(){
				// this.$nextTick(function(){
					
				// 	console.log(this.$refs.usernameInput)
				// })
				// console.log('zzzzz')
				// this.$refs.username_input.focus()
				
				},
		    // 修改性別
			changeSex(){
				// 顯示操作菜單
				uni.showActionSheet({
					itemList:sexArray,
					success: (res) => {
						this.sex = res.tapIndex
					}
				})
			},
			// 修改已婚未婚
			changeEmotion(){
				uni.showActionSheet({
					itemList:emotionArray,
					success:(res) => {
						this.emotion = res.tapIndex
					}
				})
			},
			// 修改職業
			changeJob(){
				uni.showActionSheet({
					itemList:jobArray,
					success: (res) => {
						this.job = jobArray[res.tapIndex]
					}
				})
			},
			// 修改日期
			onDateChange(e){
				// console.log(e.detail)
				this.birthday = e.detail.value
			},
			
			
			// 三級聯動
			onConfirm(e) {
				// console.log(JSON.stringify(e))
				// console.log(e)
				this.address = e.label
			},
			// 調用該三級聯動組件
			openAddres2() {
				// 根據 label 獲取
				var index = this.$refs.simpleAddress.queryIndex(this.address.split('-'), 'label');
				// console.log(index);
				// 設置默認打開的地址
				this.cityPickerValueDefault = index.index;
				// 打開三級聯動事件
				this.$refs.simpleAddress.open();
			},
			
			// 提交
			submit(){
				let obj = {
					name:this.username,
					sex:this.sex,
					qg:this.emotion,
					job:this.job,
					birthday:this.birthday,
					path:this.address
				}
				this.$H.post('/edituserinfo',obj,{
					token:true,
					native:true
				}).then(res=>{
					console.log(res);
					this.$store.commit('editUserInfo',{
						key:"username",
						value:this.username
					})
					this.$store.commit('editUserUserInfo',obj)
					uni.navigateBack({
						delta: 1
					});
					uni.showToast({
						title: '修改資料成功',
						icon: 'none'
					});
				})
			}
			
		}
	}
</script>

<style>

</style>

五 頁面通訊(重要)

uni.$off([eventName, callback]]

移除全局自定義事件監聽器。

屬性 類型 描述
eventName Array<String> 事件名
callback Function 事件的回調函數

Tips

  • 如果沒有提供參數,則移除所有的事件監聽器;
  • 如果只提供了事件,則移除該事件所有的監聽器;
  • 如果同時提供了事件與回調,則只移除這個回調的監聽器;
  • 提供的回調必須跟$on的回調為同一個才能移除這個回調的監聽器;
<template>
	<view class="content">
		<view class="data">
			<text>{{val}}</text>
		</view>
		<button type="primary" @click="comunicationOff">結束監聽</button>
		<button type="primary" @click="myclick">手動點擊</button>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				val: 0
			}
		},
		onLoad() {
			// setInterval(()=>{
			// 	uni.$emit('add', {
			// 		data: 2
			// 	})
			// },5000)
			uni.$on('add', this.add)
			// uni.$on('add', (e)=>{
			//	console.log('YYYY')
			//	this.val += e.data
			// },)
		},
		methods: {
			comunicationOff() {
				// 只有這樣才會終止掉擁有該回掉函數的監聽之間(也就是只有這樣才會只終止掉某個監聽事件)
				// 如果只寫事件名不寫回掉,則所有該監聽事件無論哪個頁面都會終止掉。
				// 如果寫事件名,隨便寫了個回掉,則無效。
				uni.$off('add', this.add)
			},
			// add(e) {
			// 	console.log('YYYY')
			// 	this.val += e.data
			// },
			myclick(e){
				uni.$emit('add', {
					data: 2
				})
			}
		}
	}
</script>

<style>
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.data {
		text-align: center;
		line-height: 40px;
		margin-top: 40px;
	}

	button {
		width: 200px;
		margin: 20px 0;
	}
</style>

六 關注點贊點踩(多組件進行通訊,很有參考價值的業務邏輯。)

效果圖:

關注效果圖:

image-20200508172425090

image-20200508172401084

點贊點踩效果圖:

對各個頁面已經加載的數據點贊點踩同步就OK。

思路

應用場景:

有很多個頁面,已經不是通知父組件就能很方便的同步時候。

比如,a、b、c 三個頁面,如果某一個組件處修改了數據后,此時abc三個頁面已經加載了一些數據,這個時候需要手動監聽並且修改abc這三個頁面相關數據,從后端同步過來另當別論。

關注邏輯:

1 比如一個頁面點擊了關注,其他頁面也要相應的把該作者的內容進行關注。

2 這個時候的其他頁面可能有很多,已經不止該common-list.vue的父組件了,所以要及時更新的頁面要用到uni.$on來進行更新。觸發用正常的emit,監聽用uni.$on(‘事件’,‘完成監聽使用的回掉函數’)

3 當需要更新的頁面卸載的時候,務必也要調用 uni.$off('之前監聽的事件名字',‘要移除掉的某個監聽事件使用的回掉函數’)

點贊點踩邏輯:

同上

精華代碼:

Common-list.vue

// 關注事件
			follow(){
				//console.log('點擊了關注')
				// 通知父組件
				// 通過權限驗證,提交后台已經關注
				console.log(this.item)
				this.checkAuth(()=>{
					this.$H.post('/follow',{
						follow_id:this.item.user_id
					},{
						token:true,
						native:true
					}).then(res=>{
						console.log(res)
						// 通知詳情頁面更新
						if (this.isdetail){
							this.$emit('follow')
						}
						// 
						// 通知更新
						uni.$emit('updateFollowOrSupport',{
							type:"follow",
							data:{
								user_id:this.item.user_id
							}
						})
				})})

index.vue

onLoad() {
			uni.getSystemInfo({
				success:res=>{
								// 可用窗口高度(屏幕高度-導航欄高度-底部欄高度。) -  選項卡高度
					this.scrollH = res.windowHeight - uni.upx2px(101)
					// console.log(this.scrollH)
				}
			})
			// 根據選項生成列表
			this.getData()
			
			// 監聽點踩操作進行數據更新。 
			uni.$on('updateFollowOrSupport' ,this.listionFollowOrSupport)
			
		},
		onUnload() {
     																	 // ps: 只有寫了事件名和回掉函數對應的監聽事件,才能准確的
                                       //      移除掉使用了該回掉函數函數的那一個監聽事件。
      // 這里的回掉並不會執行,你可以這么理解,只是回掉函數地址+事件名來精准的定位到一個需要釋放的監聽事件
			uni.$off('updateFollowOrSupport',this.listionFollowOrSupport)
		},
      
methods: {
			// 封裝成回掉得意移除頁面的時候停止監聽
			listionFollowOrSupport(e){
				console.log('index.vue 接受到了')
				switch (e.type){
					case 'follow': // 關注
					this.follow(e.data.user_id)
						break;
					case 'support':
					this.doSupport(e.data)
					default:
						break
				}
			},
      follow(user_id){
				// this.newsList[this.tabIndex].list[e].isFollow = true
				// uni.showToast({title:'關注成功'})
				// console.log(this.newsList)
				this.newsList.forEach(tab=>{
					tab.list.forEach(item=>{
						if (item.user_id === user_id){
							item.isFollow = true
						}
					})
				})
			},
      doSupport(e){
				// 拿到當前隊對象
				this.newsList[this.tabIndex].list.forEach(item=>{
					// console.log(e)
					// 除非item拿到的是簡單類型或手動深拷貝,否則皆為淺拷貝
					// 第一層深拷貝可以考慮做一個{},往里面添加值的形式做到第一層深拷貝
					if (item.id === e.id){
						// console.log('處理前',this.newsList[this.tabIndex].list)
						if (item.support.type === ''){
							item.support[e.type+'_count']++
						} else if (item.support.type === 'support' && e.type === 'unsupport'){
							// 頂 -1
							item.support.support_count--;
							// 踩 +1
							item.support.unsupport_count++;
						} else if (item.support.type === 'unsupport' && e.type === 'support'){
							// 踩 -1
							item.support.unsupport_count --;
							// 頂 +1
							item.support.support_count ++;
						}
						item.support.type = e.type
						// console.log('處理后說明是淺拷貝,影響原來的列表,vue搜集到了直接渲染',this.newsList[this.tabIndex].list)
					}
				})
				let msg = e.type === 'support' ? '頂' : '踩'
				
				uni.showToast({
					title:msg+'成功'
				})
				
				
			}
      

detail.vue

onLoad(e) {
			// 初始化
			if (e.detail){
				this.__init(JSON.parse(e.detail))
			}
			
			// 監聽關注頂踩操作。
				
			uni.$on('updateFollowOrSupport',this.listionFollowOrSupport)
			
		},
onUnload() {
			uni.$off('updateFollowOrSupport',this.listionFollowOrSupport)
		},
      
methods: {
			listionFollowOrSupport(e){
				console.log('detail.vue 接受到了')
				switch (e.type){
					case 'follow': // 關注
					this.follow(e.data.user_id)
						break;
					case 'support':
					this.doSupport(e.data)
					default:
						break
				}
			},
      follow(){
				this.info.isFollow = true
				uni.showToast({
					title:'關注成功'
				})
			},
      doSupport(e){
				// 之前操作過
				if (this.info.support.type === e.type) {
					return uni.showToast({
						title: '你已經操作過了',
						icon: 'none'
					});
				}
				let msg = e.type === 'support' ? '頂' : '踩'
				// 之前沒有操作過
				if (this.info.support.type === '') {
					this.info.support[e.type+'_count']++
				}else if(this.info.support.type === 'support' && e.type === 'unsupport'){				
					// 頂 - 1
					this.info.support.support_count--;
					// 踩 + 1
					this.info.support.unsupport_count++;
				}else if(this.info.support.type === 'unsupport' && e.type === 'support'){			   
					// 頂 + 1
					this.info.support.support_count++;
					// 踩 - 1
					this.info.support.unsupport_count--;
				}
				this.info.support.type = e.type
				uni.showToast({
					title: msg
				});
			},

search.vue

onUnload() {
			if(this.type === 'post'){
				uni.$off('updateFollowOrSupport')
			}
		},
onLoad(e) {
        if (e.type) {
          this.type = e.type
        }
        let pageTitle = '帖子'
        switch (this.type){
          case 'post':
            pageTitle = '帖子'
            uni.$on('updateFollowOrSupport',(e)=>{
              switch (e.type){
                case 'follow': // 關注
                  this.follow(e.data.user_id)
                  break;
                default:
                  break;
              }
            })
            break;
          case 'topic':
            pageTitle = '話題'
            break;
          case 'user':
            pageTitle = '用戶'
            break;
        }
  
  
methods:{
  follow(user_id){
				// 找到當前作者的所有列表
				this.searchList.forEach((item)=>{
					if(item.user_id === user_id){
						item.isFollow = true
					}
				})
				uni.showToast({ title: '關注成功' })
			},
    
  }

七 判斷一個對象是否為空

1 JSON.stringfy判斷

    if (JSON.stringify(data) === '{}') {
        return false // 如果為空,返回false
    }
    return true // 如果不為空,則會執行到這一步,返回true

2 通過object.keys(),如果為空則會返回空【】,就可以length判斷了

如果我們的對象為空,他會返回一個空數組,如下:

    var a = {}
    Object.keys(a) // []
我們可以依靠Object.keys()這個方法通過判斷它的長度來知道它是否為空。

    if (Object.keys(object).length === 0) {
        return false // 如果為空,返回false
    }
    return true // 如果不為空,則會執行到這一步,返回true

八 發布文章功能實現(選擇圖片直接上傳功能,可以關注草稿功能)

效果圖:

image-20200509214158691

image-20200509214223034

image-20200509214252692

思路:

1 重新修改了一下上傳圖片組件,直接選中就可以請求后端。

2 做了一個誰可見的訪問權限的選擇列表(uni.showActionSheet實現)

3 做了一個選擇課程類型的普通picker框(滾動選擇)

3 然后話題直接用的之前的topic.nav 頁面,然后用一個choose:true參數來控制

4 還有當跳轉過去獲取想要的數據后,使用$on進行跨組件傳參。

Code add-input:

<template>
	<view>
		<!-- 自定義導航條 -->
		<uni-nav-bar left-icon="back" :border="false" :statusBar="true" @click-left="goBack">
			<view class="flex align-center justify-center w-100" @click="changeIsopen">
				<text class="font">{{isOpenText}}</text><text class="iconfont icon-shezhi ml-1"></text>
			</view>
		</uni-nav-bar>
		
		<!-- 文本域 -->
		<view class="px-1">
			<!-- 不要給textarea 直接設置px-1 否則會出現橫向滾動條問題。關於這個文本域配置到時候實操的時候再說 -->
			<textarea v-model="content"   placeholder="說一句話吧" class="uni-textarea"/>
		</view>
		
		
		<!-- 選中的分類 -->
		<view class="font-md px-2 py-1 flex">
			<view class="border px-3 py main-color main-border-color flex align-center justify-center" style="border-radius: 50rpx;">
				<text class="iconfont icon-huati mr-1"></text>
				{{post_class_name ? "所屬分類:"+post_class_name : "請選擇分類"}}
			</view>
		</view>
		
		<!-- 選中的話題 -->
		<view class="font-md px-2 py-1 flex">
			<view class="border px-3 py main-color main-border-color flex align-center justify-center" style="border-radius: 50rpx;">
				<text class="iconfont icon-huati mr-1"></text>
				{{topic.title ? "所屬話題:"+topic.title : "請選擇話題"}}
			</view>
		</view>
		
		<!-- 多圖上傳 --> 
		<upload-image :list="imageList" :show="showTag" ref="uploadImage" @change="changeImage" ></upload-image>
		
		<!-- 底部操作條 -->
		<view class="fixed-bottom bg-white flex align-center" style="height: 85rpx;"> 
			<!-- 選擇文章分類 -->
			<picker mode="selector" :range="post_class_list" @change="choosePostclass">
				<view class="iconfont icon-caidan footer-btn animated " hover-class="jello"></view>
			</picker>
			<!-- 選擇文章話題 -->
			<view class="iconfont icon-huati footer-btn animated " hover-class="jello" @click="chooseTopic"></view>
			<view class="iconfont icon-tupian footer-btn animated " hover-class="jello" @click="iconClickEvent('uploadImage')"></view>
			<!-- 小點  當一行flex元素作用浮動可以使用margin-right 或者 margin-left 靠左或者靠右邊 -->
			<!-- 發送按鈕 -->
			<view 
			class="bg-main text-white ml-auto flex justify-center align-center rounded mr-2 animated" 
			hover-class="jello" 
			style="width: 140rpx;height: 60rpx;"
			@click="submit">發送</view>
		</view>
		

	</view>
</template>

<script>
	const isOpenArray = ['僅自己可見' , '所有人可見']
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue'
	import uploadImage from '@/components/common/upload-image.vue'
	
	export default {
		components:{
			uniNavBar,
			uploadImage
		},
		data() {
			return {
				content:"",
				imageList:[],
				backTag:true,
				isopen:1,
				post_class_list:[],
				post_class_index:-1,
				topic:{
					title:'',
					id:0
				},
				
			}
		},
		computed:{
			showTag() {
				return this.imageList.length>0
			},
			isOpenText(){
				return isOpenArray[this.isopen]
			},
			post_class_name(){
				if(this.post_class_index !== -1){
					return this.post_class_list[this.post_class_index]
				}
			}
			
		},
		// 監聽返回
		onBackPress(){
			if ((this.content!='' || this.imageList.length >0) && this.backTag){
				// 異步的
				uni.showModal({
					content:'是否要保存為草稿?',
					showCancel:true,
					
					cancelText:'不保存',
					confirmText:'保存',
					success: (res) => {
						// 點擊確認
						if (res.confirm) {
							// 保存到本地緩存。
							this.store()
						}else { // 點擊取消,清除本地緩存
							uni.removeStorage({
								key:"add-input"
							})
							
						}
						
						// 手動執行返回
						uni.navigateBack({
							delta:1
						})
					}	,
					
				})
				// 到這里相當於提示框已經出現過或者將要出現了。第二次阻止后退就不應該了
				this.backTag = false
				return true // 返回true阻止默認行為
			}
			
		},
		// 頁面加載的時
		onLoad() {
			uni.getStorage({
				key:"add-input",
				success: (res) => {
					console.log(res)
					if (res.data){
						let result = JSON.parse(res.data)
						this.content = result.content
						this.imageList = result.imageList
					}
				}
			})
			uni.$on('chooseTopic',this.chooseTopicBack)
			
			// 獲取所有分類
			this.getPostClass();
		},
		onUnload() {
		    uni.$off('chooseTopic',this.chooseTopicBack)
		},
		methods: {
			goBack() {
				uni.navigateBack({
					delta: 1
				})
			},
			//選中圖片
			changeImage(e){
				this.imageList = e
				// console.log('changeimage',e)
			},
			// 
			store(){
				let obj = {
					content:this.content,
					imageList:this.imageList
				}
				// 異步新增本地緩存。
				uni.setStorage({
					key:'add-input',
					data:JSON.stringify(obj)
				})
			},
			// 底部圖片點擊時間
			iconClickEvent(e){ 
				switch (e){
					case 'uploadImage':
					// 通過這宗方式使用子組件里面的方法。
					this.$refs.uploadImage.chooseImage()
						break;
					
				}
			},
			// 切換是否所有人可見權限
			changeIsopen(){
				uni.showActionSheet({
					itemList:isOpenArray,
					success:(res)=>{
						this.isopen = res.tapIndex
					}
				})
			},
			
			// 獲取文章分類
			getPostClass(){
				this.$H.get('/postclass').then(res=>{
					// console.log(res)
					this.post_class_list = res.list.map(item=>{
						return item.classname
					})
				}).catch(err=>{
					console.log(err)
				})
			},
			
			// 選擇文章類型
			choosePostclass(e){
				this.post_class_index = e.detail.value
				
			},
			
			// 選擇文章話題
			chooseTopic(e){
				uni.navigateTo({
					url:'../topic-nav/topic-nav?choose=true'
				})
			},
			
			// 監聽選擇的話題
			chooseTopicBack(res){
				this.topic = res
			},
			
			// 發送
			submit(){
				if(this.topic.id == 0){
					return uni.showToast({
						title: '請選擇話題',
						icon: 'none'
					});
				}
				if(this.post_class_index == -1){
					return uni.showToast({
						title: '請選擇分類',
						icon: 'none'
					});
				}
				uni.showLoading({
					title: '發布中...',
					mask: false
				});
				let imageList = this.imageList.map(item=>{
					return {id:item.id}
				})
				console.log(imageList)
				this.$H.post('/post/create',{
					// 發送
					imglist:JSON.stringify(imageList),
					text:this.content,
					isopen:this.isopen,
					topic_id:this.topic.id,
					post_class_id:this.post_class_index	
				},{
					token:true
				}).then(res=>{
					uni.hideLoading()
					this.backTag = false
					uni.navigateBack({
						delta:1
					})
					uni.showToast({
						title:'發布成功'
					})
				}).catch(err=>{
					console.log(err)
					uni.hideKeyboard()
				})
			}
			
		}
	}
</script>

<style>
.footer-btn{
	height:86rpx;
	width:86rpx;

	display:flex;
	justify-content: center;
	align-items:center;
	font-size:50rpx;
	
}

</style>

code upload-image.vue

<template>
	<view>

		<view class="py-2" v-if="show">
			<view class="uni-uploader">
				<view class="uni-uploader-head">
					<view class="uni-uploader-title p-1">點擊可預覽選好的圖片</view>
					<view class="uni-uploader-info">{{imageList.length}}/9</view>
				</view>
				<view class="uni-uploader-body">
					<view class="uni-uploader__files">
						<block v-for="(image,index) in imageList" :key="index">
							<view class="uni-uploader__file position-relative">
								<image class="uni-uploader__img rounded " mode="aspectFill" :src="image.url" :data-src="image" @tap="previewImage"></image>
								<!-- 刪除圖片的地方 -->
								<view class="position-absolute top-0 right-0 rounded px-1" style="background-color: rgba(0,0,0,0.5); " 
								@click.stop="deleteImage(index)">
									<text class="iconfont icon-shanchu text-white"></text>
								</view>
							</view>
							
						</block>
						<view class="uni-uploader__input-box rounded">
							<view class="uni-uploader__input" @tap="chooseImage"></view>
						</view>
					</view>
				</view>
			</view>

		</view>
	</view>
</template>
<script>
	import permision from "@/common/permission.js"
	var sourceType = [
		['camera'],
		['album'],
		['camera', 'album']
	]
	var sizeType = [
		['compressed'],
		['original'],
		['compressed', 'original']
	]
	export default {
		props:{
			list:Array,
			show:{
				type:Boolean,
				default:true
			}
		},
		data() {
			return {
				title: 'choose/previewImage',
				imageList: [],
				sourceTypeIndex: 2,
				sourceType: ['拍照', '相冊', '拍照或相冊'],
				sizeTypeIndex: 2,
				sizeType: ['壓縮', '原圖', '壓縮或原圖'],
				countIndex: 8,
				count: [1, 2, 3, 4, 5, 6, 7, 8, 9]
			}
		},
		mounted() {
			 // console.log('onready onready')
			 this.imageList = this.list
			 console.log('測試',this.imageList)
		},
		onUnload() {
			this.imageList = [],
				this.sourceTypeIndex = 2,
				this.sourceType = ['拍照', '相冊', '拍照或相冊'],
				this.sizeTypeIndex = 2,
				this.sizeType = ['壓縮', '原圖', '壓縮或原圖'],
				this.countIndex = 8;
		},
		methods: {
			// 刪除圖片
			deleteImage(index){
				uni.showModal({
					title:'提示',// 
					content:'是否刪除該圖片?', //
					showCancel:true, // 
					cancelText:'不刪除',
					confirmText:'刪除',
					success:res => {
						if (res.confirm){
							this.imageList.splice(index,1)
							this.$emit('change',this.imageList)
						}
					}
				})
			},
			chooseImage: async function() {
				// #ifdef APP-PLUS
				// TODO 選擇相機或相冊時 需要彈出actionsheet,目前無法獲得是相機還是相冊,在失敗回調中處理
				if (this.sourceTypeIndex !== 2) {
					let status = await this.checkPermission();
					if (status !== 1) {
						return;
					}
				}
				// #endif

				if (this.imageList.length === 9) {
					let isContinue = await this.isFullImg();
					console.log("是否繼續?", isContinue);
					if (!isContinue) {
						return;
					}
				}
				uni.chooseImage({
					sourceType: sourceType[this.sourceTypeIndex],
					sizeType: sizeType[this.sizeTypeIndex],
					count: this.imageList.length + this.count[this.countIndex] > 9 ? 9 - this.imageList.length : this.count[this.countIndex],
					success: (res) => {
						// console.log(res)
						// 選擇照片成功后直接到這個接口發送給后端並且通知父組件,不如直接傳到阿里雲里這個位置,暫時先這么着把
						res.tempFilePaths.forEach(item=>{
							this.$H.upload('/image/uploadmore',{
								filePath: item,
								name: 'imglist[]',
								token:true
							}).then(result=>{
								// console.log(result)
								// 上傳成功后組織該頁面的imageList
								this.imageList.push(result.data.list[0])
								// 然后通知父組件
								this.$emit('change',this.imageList)
							}).catch(err=>{
								console.log(err)
							})
						})
						
						
						
						// this.imageList = this.imageList.concat(res.tempFilePaths);
						// 選擇好后通知父組件
						// this.$emit('change', this.imageList)
					},
					fail: (err) => {
						// #ifdef APP-PLUS
						if (err['code'] && err.code !== 0 && this.sourceTypeIndex === 2) {
							this.checkPermission(err.code);
						}
						// #endif
						// #ifdef MP
						uni.getSetting({
							success: (res) => {
								let authStatus = false;
								switch (this.sourceTypeIndex) {
									case 0:
										authStatus = res.authSetting['scope.camera'];
										break;
									case 1:
										authStatus = res.authSetting['scope.album'];
										break;
									case 2:
										authStatus = res.authSetting['scope.album'] && res.authSetting['scope.camera'];
										break;
									default:
										break;
								}
								if (!authStatus) {
									uni.showModal({
										title: '授權失敗',
										content: 'Hello uni-app需要從您的相機或相冊獲取圖片,請在設置界面打開相關權限',
										success: (res) => {
											if (res.confirm) {
												uni.openSetting()
											}
										}
									})
								}
							}
						})
						// #endif
					}
				})
			},
			isFullImg: function() {
				return new Promise((res) => {
					uni.showModal({
						content: "已經有9張圖片了,是否清空現有圖片?",
						success: (e) => {
							if (e.confirm) {
								this.imageList = [];
								res(true);
							} else {
								res(false)
							}
						},
						fail: () => {
							res(false)
						}
					})
				})
			},
			previewImage: function(e) {
				var current = e.target.dataset.src
				uni.previewImage({
					current: current,
					urls: this.imageList
				})
			},
			async checkPermission(code) {
				let type = code ? code - 1 : this.sourceTypeIndex;
				let status = permision.isIOS ? await permision.requestIOS(sourceType[type][0]) :
					await permision.requestAndroid(type === 0 ? 'android.permission.CAMERA' :
						'android.permission.READ_EXTERNAL_STORAGE');

				if (status === null || status === 1) {
					status = 1;
				} else {
					uni.showModal({
						content: "沒有開啟權限",
						confirmText: "設置",
						success: function(res) {
							if (res.confirm) {
								permision.gotoAppSetting();
							}
						}
					})
				}

				return status;
			}
		}
	}
</script>

<style>
	.cell-pd {
		padding: 22upx 30upx;
	}

	.list-pd {
		margin-top: 50upx;
	}
</style>

code 話題相關代碼(略)

九 實現我的帖子數,動態,評論,粉絲數量頁面(watch擴展用法)

效果圖(略)

思路:

每當顯示頁面的時候根據登錄狀態去請求數據並且渲染。

退出的時候watch登錄狀態,如果為非登錄狀態則清空數據。

代碼:

onShow(){
			// 獲取當前的評論數各種數據
			// 如果登錄了
			if(this.loginStatus){
				this.getCounts()
			}	
		}



watch:{
			// 監聽(新值,舊值)
			loginStatus(newValue,oldValue) {
				console.log(newValue,oldValue)
				if(newValue){
					this.getCounts()
				}else{
					this.myData.forEach(item=>{
						item.num = 0
					})
				}
			}
			
		},

十 評論實現

明天回來把那啥組件傳送信息完善了。。。。。。媽的

整理前的數據

{
	"list": [{
		"id": 574,
		"user_id": 328,
		"fid": 0,
		"fnum": 1,
		"data": "哈哈哈哈",
		"create_time": 1578619011,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 575,
		"user_id": 328,
		"fid": 0,
		"fnum": 1,
		"data": "哈哈哈還好",
		"create_time": 1578619225,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 576,
		"user_id": 328,
		"fid": 0,
		"fnum": 1,
		"data": "哥趕緊看看換個",
		"create_time": 1578619261,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 577,
		"user_id": 328,
		"fid": 0,
		"fnum": 0,
		"data": "u好炒粉干",
		"create_time": 1578619268,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 578,
		"user_id": 328,
		"fid": 0,
		"fnum": 0,
		"data": "滾滾滾",
		"create_time": 1578620553,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 579,
		"user_id": 328,
		"fid": 574,
		"fnum": 1,
		"data": "好好干方",
		"create_time": 1578620589,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 580,
		"user_id": 328,
		"fid": 579,
		"fnum": 0,
		"data": "哈哈哈哈唱個歌和我",
		"create_time": 1578620846,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 581,
		"user_id": 328,
		"fid": 575,
		"fnum": 0,
		"data": "不會",
		"create_time": 1578621432,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 582,
		"user_id": 328,
		"fid": 0,
		"fnum": 0,
		"data": "海港城",
		"create_time": 1578621462,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}, {
		"id": 583,
		"user_id": 328,
		"fid": 576,
		"fnum": 0,
		"data": " 幾號發貨",
		"create_time": 1578623609,
		"post_id": 272,
		"user": {
			"id": 328,
			"username": "掌上",
			"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg"
		}
	}]
}

整理后的數據

[{
	"id": 574,
	"fid": 0,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:16",
	"data": "哈哈哈哈"
}, {
	"id": 579,
	"fid": 574,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:43",
	"data": "好好干方"
}, {
	"id": 580,
	"fid": 579,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:47",
	"data": "哈哈哈哈唱個歌和我"
}, {
	"id": 575,
	"fid": 0,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:20",
	"data": "哈哈哈還好"
}, {
	"id": 581,
	"fid": 575,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:57",
	"data": "不會"
}, {
	"id": 576,
	"fid": 0,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:21",
	"data": "哥趕緊看看換個"
}, {
	"id": 583,
	"fid": 576,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 10:33",
	"data": " 幾號發貨"
}, {
	"id": 577,
	"fid": 0,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:21",
	"data": "u好炒粉干"
}, {
	"id": 578,
	"fid": 0,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:42",
	"data": "滾滾滾"
}, {
	"id": 582,
	"fid": 0,
	"userid": 328,
	"userpic": "https://ceshi2.dishait.cn//uploads/20200107/d0698c09b65f209a37f9646e8eb95af0.jpg",
	"username": "掌上",
	"time": "2020-01-10 上午 9:57",
	"data": "海港城"
}]

思路:

1 一定是從后端開始設計的

2 前端根據數據進行樣式渲染

3 渲染完成后通知index.vue頁面

3 需要注意的是問題寶典里面的內容

// 問題寶典 1
			 // 1 點擊了別處已經失去了焦點,但是如果不手動設置focus依然為true
			 // 2 如果focus不為false,把focus更新為true無效,所以失去焦點的時候一定要把focus設置為false
			 // 3 問題出在了我已經獲取到了焦點,但是點擊了別的評論這個時候,
				// 1 先經歷了個blur失去焦點自動促發
				// 2 又經歷了個點擊reply獲取焦點的事件,但是獲取焦點無效。
				// 我的目的:”點擊了別的評論不要收起鍵盤,不收起鍵盤的這個事兒是目前沒轍,
				// 目前的替代方案是用nextTick來解決等待數據都渲染完成,然后再執行獲取焦點事件。但是會導致慢。“
// 問題寶典 2 (待定)
			// 有時候點擊彈起不彈起問題

detail.vue

<template>
	<view>
		<common-list :item='info' isdetail 
		@follow="follow"
		@doSupport="doSupport">
			
				<view class="flex font-md align-center">
					{{info.title}}
				</view>
				<view class="flex font align-center">
					{{info.content}}
				</view>
				<!-- widthFix這個只是裁剪方式,跟具體寬度無關 -->
				<block v-for="(item,index) in info.images" :key="index">
					<image :src="item.url" class='w-100' mode="widthFix"
					@click="preview(index)"></image>
				</block>
		</common-list>
		
		
		<divider></divider>
		<!-- copy官方評論組件 -->
		<view class="p-2 font-md font-weight-bold">
			最新評論 {{info.comment_count}}
		</view>
		<!-- <view class="px-2">
			<view class="uni-comment-list">
				<view class="uni-comment-face"><image src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/uni@2x.png" mode="widthFix"></image></view>
				<view class="uni-comment-body">
					<view class="uni-comment-top">
						<text>小貓咪</text>
					</view>
					<view class="uni-comment-content">支持國產,支持DCloud!</view>
					<view class="uni-comment-date">
						<view>2天前</view>
					</view>
				</view>
			</view>
		</view> -->
		
		<!-- // copy 評論組件 -->
		<view class="px-2">
			<view class="uni-comment-list" 
			v-for="(item,index) in comments"
			:key="index">
				<view v-if="item.fid" style="width: 60rpx;"></view>
				<view class="flex w-100"
				:class="item.fid ? 'bg-light rounded p-2' : ''">
					<view class="uni-comment-face"><image :src="item.userpic"></image></view>
					<view class="uni-comment-body">
						<view class="uni-comment-top">
							<text>{{item.userid===info.user_id ?'樓主':item.username}}</text>
						</view>
						<view class="uni-comment-content "
						@click="reply(item.id,item.userid===info.user_id ?'樓主':item.username)"
						hover-class="text-main">{{item.data}}</view>
						<view class="uni-comment-date">
							<view>{{item.time}}</view>
						</view>
					</view>
				</view>
			</view>
			
		</view>
		<input  class="border" type="text" ref="input">
		
		<!-- 空白高度占位,使得有內容的部分不要被底部評論框擋住。 -->
		<view style="height: 100rpx;"></view>
		<bottom-input :to-user="toUser"  :focus='focus' @blur="blur" @submit="submit"></bottom-input>
		
		<!-- 分享下拉彈出框 -->
		<more-share ref="share"></more-share>
	</view>
</template>

<script>
	import commonList from '@/components/common/common-list.vue'
	import bottomInput from '@/components/common/bottom-input.vue'
	import moreShare from '@/components/common/more-share.vue'
	import $T from '@/common/time.js';
	export default {
		components:{
			commonList,
			bottomInput,
			moreShare
		},
		data() {
			return {
				// 當前帖子信息
				href:"",
				info:{
					id:"",
					username:"",
					userpic:"",
					newstime:"",
					isFollow:false,
					title:"",
					titlepic:"",
					support:{
						type:"support", // 頂
						support_count:0,
						unsupport_count:0
					},
					comment_count:0,
					share_num:0,
					content:"",
					images:[]
				},
				toUser:"請輸入評論",
				comments:[],
				focus:false,
				reply_id:0
			}
		},
		computed:{
			imagesList(){
				
								//數組取出來每個元素,然后每個元素進行操作后,組成新的數組。 
				return this.info.images.map(item=>item.url)
			}
		},
		// 接受傳參
		onLoad(e) {
			// 初始化
			if (e.detail){
				this.__init(JSON.parse(e.detail))
			}
			
			// 監聽關注頂踩操作。
			uni.$on('updateFollowOrSupport',this.listionFollowOrSupport)
			
			
			
			
		},
		onUnload() {
			uni.$off('updateFollowOrSupport',this.listionFollowOrSupport)
		},
		// 點擊導航欄按鈕觸發的事件
		onNavigationBarButtonTap(){
			// console.log(this.info.titlepic)
			//打開下拉框,以及傳入分享需要的信息
				this.$refs.share.open({
					title:this.info.title,
					shareText:this.info.content,
					href:this.href ? this.href:'https://www.baidu.com/',
					image:this.info.titlepic? this.info.titlepic:'https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1587542604&di=2601975188b590defa2e0cb432ccc1b3&src=http://pic.feizl.com/upload/allimg/170918/18362zf1lsf3e0a.jpg'
				})
		},
		// 手機返回觸發的事件
		onBackPress(){
				// console.log(zz)
				// console.log('zz')
				this.$refs.share.close()
		},
		methods: {
			listionFollowOrSupport(e){
				console.log('detail.vue 接受到了')
				switch (e.type){
					case 'follow': // 關注
					this.follow(e.data.user_id)
						break;
					case 'support':
					this.doSupport(e.data)
					default:
						break
				}
			},
			__init(data){
				// 修改標題
				// console.log('222',data)
				uni.setNavigationBarTitle({
					title:data.title
				})
				this.info = data
				console.log(this.info)
				this.$H.get('/post/'+data.id).then(res=>{
					this.info.content = res.detail.content
					// 發現問題,vue沒有檢測到info下的images數據更新
					// this.info.images = res.detail.images
					
					
					// 解決方案一 對象嵌套數組,數組嵌套對象,使得vue檢測到該數據進行了更新。
					this.$set(this.info,'images',res.detail.images)
					
					// console.log(this.info)
					// 解決方案二,強制更新vue所有實例數據。
					// this.$forceUpdate 強制更新vue所有實例數據
					
					// 解決方案三,如果邏輯允許,直接把嵌套的深數據放到data的根層,這樣就能檢測到了。
					// console.log(this.info)
				})
				// 獲取評論
				this.getComments()
			},
			// 子組件觸發的關注事件
			follow(){
				this.info.isFollow = true
				uni.showToast({
					title:'關注成功'
				})
			},
			// 子組件觸發的頂踩事件
			doSupport(e){
				// 之前操作過
				if (this.info.support.type === e.type) {
					return uni.showToast({
						title: '你已經操作過了',
						icon: 'none'
					});
				}
				let msg = e.type === 'support' ? '頂' : '踩'
				// 之前沒有操作過
				if (this.info.support.type === '') {
					this.info.support[e.type+'_count']++
				}else if(this.info.support.type === 'support' && e.type === 'unsupport'){				
					// 頂 - 1
					this.info.support.support_count--;
					// 踩 + 1
					this.info.support.unsupport_count++;
				}else if(this.info.support.type === 'unsupport' && e.type === 'support'){			   
					// 頂 + 1
					this.info.support.support_count++;
					// 踩 - 1
					this.info.support.unsupport_count--;
				}
				this.info.support.type = e.type
				uni.showToast({
					title: msg
				});
			},
			// 預覽圖片
			preview(index){
				// 預覽圖片
				uni.previewImage({
					current:index,
					urls:this.imagesList
				})
			},

			// // 關閉評論框
			// close(){
			// 	this.$refs.share.close()
			// }
			// 獲取評論列表
			getComments(){
				// console.log('aaa')
				this.$H.get('/post/'+this.info.id+'/comment',{},{
					// native:true
				})
				.then(res=>{
					// console.log(res)
					this.comments = this.__ArrSort(res.list)
					// console.log('zzzz')
					console.log(this.comments)
					this.info.comment_count = this.comments.length
					// 明天回來的時候直接,把這個傳送index組件完成。。。
					uni.$emit('updateCommentsCount',{
						id:this.info.id,
						count:this.info.comment_count
					})
				})
			},
			// 重新整理評論格式
			__ArrSort(arr,id = 0){
				var temp = [],lev=0;
				var forFn = function(arr, id,lev){
					for (var i = 0; i < arr.length; i++) {
						var item = arr[i];
						if (item.fid==id) {
							item.lev=lev;
							temp.push({
								id:item.id,
								fid:item.fid,
								userid:item.user.id,
								userpic:item.user.userpic,
								username:item.user.username,
								time:$T.gettime(item.create_time),
								data:item.data,
							});
							forFn(arr,item.id,lev+1);
						}
					}
				};
				forFn(arr, id,lev);
				return temp;
			},
			// 提交評論
			submit(data){
				if(data === ''){
					return uni.showToast({
						title: '評論不能為空',
						icon: 'none'
					});
				}
				uni.showLoading({
					title: '評論中...',
					mask: false
				});
				console.log(this.reply_id)
				this.$H.post('/post/comment',{
					fid:this.reply_id,
					data:data,
					post_id:this.info.id
				},{
					token:true
				}).then(res=>{
					// console.log(res)
					
					uni.hideLoading()
					this.getComments()
				}).catch(err=>{
					console.log(err)
					uni.hideLoading()
					if (err.errorCode === 20008){
						uni.navigateTo({
							url:'../user-phone/user-phone'
						})
						uni.showToast({
							title:err.msg,
							icon:'none'

						})
					}
				})
			},
			// 點擊該評論會觸發  
			reply(id,toUserName){
				// 有可能blur馬上發生
				this.$nextTick(()=>{
					// console.log(this)
					// console.log(this.$refs)
					// console.log(this.$refs.input1)
				    // console.log('zzzz',this.$refs.input)
					console.log('監聽到了reply')
					this.toUser = "回復"+toUserName+": "
					this.reply_id = id
					this.focus = true
					console.log(this.focus)
				});
				
			},
			
				
			
			// 收起鍵盤、點擊別處、會觸發。
			blur(){
				
				console.log('監聽到了blur')
				// this.reply_id = 0
				// if (this.reply_id){
					
				// }
				this.focus = false
				this.toUser = "請輸入評論: "
				console.log(this.focus)
			}
			
			// 這就包括了一種情況:點擊了別處 但是點擊的是評論,這個時候不應該收起鍵盤
		}
	}
</script>

<style>

</style>

Bottom-input.vue

<template>
	<view>
		<!-- 底部操作條 -->
		<view style="height: 100rpx;"
		class="fixed-bottom flex align-center border-top bg-light">
			<input  type="text"  v-model="content" class="flex-1 rounded  ml-2 bg-white" style="padding:10rpx;" 
			ref="input1"
			:focus="focus"
			@blur="blur"
			:placeholder="toUser"
			@confirm="submit"/>
			<view ></view>
			<!-- 上面的confirm 可以使得input框直接回車就提交了。 :focus 可以直接獲取焦點 @blur 失去焦點-->

			
			
			<view class="iconfont icon-fabu flex align-center justify-center font-lger animated"  
			hover-class="jello text-main" style="width: 100rpx;"
			@click="submit">
				
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props:{
			toUser:{
				type:String,
				default:'請輸入評論',
				
			},
			focus:{
				type:Boolean,
				default:false
			}
		},
		data() {
			return {
				content:"",
				
				
			};
		},
		watch:{
			focus(newfocus,oldfocus){
				console.log(newfocus,oldfocus)
			}
		},
		methods:{
			submit(){
				// console.log(this.toUser)
				if (this.content===''){
					return uni.showToast({
						title:"消息不能為空",
						icon:'none'	
					})
				}
				this.$emit('submit',this.content)
				// 清空輸入框
				this.content = ''
			},
			blur:function () {
				
				// console.log('blur',this,this.$refs.input);
				// this.$refs.input.focus();
				  // if(this.$refs.input){
					  // uniapp沒有$refs內置dom功能
				  //   this.$refs.input.focus();
				  // }else{
				// this.$nextTick(()=>{
				// 	// console.log(this)
				// 	// console.log(this.$refs)
				// 	// console.log(this.$refs.input1)
				//     this.$refs.input1.focus();
				// });
				  // }
				// 通知父親組件  提交的時候會觸發  blur事件
				this.$emit('blur')
				
				// this.focus = false
				// this.focus = true
				
			}
		}
		
	}
</script>

<style>

</style>

十一 關注好友動態:

效果圖:

image-20200512124734867

思路:

兩種請求數據的方式:

1 onshow 請求數據,並且每次onshow的時候page=1,這樣保證了每次顯示該頁面都拿到最新的數據

2 下拉加載顯示更多。page不斷+1

代碼:

onShow() {
			// 這就做到了 每當顯示這個頁面的的時候關注的是最新的
			this.page = 1
			this.getList()
		},
// 獲取關注好友文章列表
			getList(){
				let isrefresh = this.page === 1
				this.$H.get('/followpost/'+this.page,{},{
					token:true,
					noExtoken:true
				}).then(res=>{
					let list = res.list.map(v=>{
						return this.$U.formatCommonList(v)
					})
					this.list = isrefresh ? list : [...this.list,...list];
					this.loadmore  = list.length < 10 ? '沒有更多了' : '上拉加載更多';
				}).catch(err=>{
					if(!isrefresh){
						this.page--;
					}
				})
			},
loadmoreEvent(){
				// 驗證當前是否處於可加載狀態
				if (this.loadmore !== '上拉加載更多') return;
				// 設置加載狀態
				this.loadmore = '加載中...'
				// 請求數據
				this.page++
				this.getList()
			},

十二 我的好友列表實現(略)

<template>
	<view>
		<!-- 默認最新選項卡 -->
		<!-- 注意padding會把高度撐高,botter下邊框要多給點距離。在下面剪掉這個距離-->
		<!-- 總元素的寬度=寬度+左填充+右填充+左邊框+右邊框+左邊距+右邊距 -->
		<!-- 總元素的高度=高度+頂部填充+底部填充+上邊框+下邊框+上邊距+下邊距 -->
		<view class=" flex align-center" style="height: 100rpx;">
			<view class="font flex-1 flex align-center justify-center font-weight-bold"
			v-for="(item,index) in tabBars" :key="index"
			
			:class="index===tabIndex?'text-main font-lg':''"
			@click="changeTab(index)"
			>{{item.name}}</view>
		</view>
		
		<swiper :duration="150" :current="tabIndex" @change="onChangeTab"
		:style="'height:'+scrollH+'px'">
		<!-- 會默認分配索引 0 1 2 3 4 5  -->
			<swiper-item v-for="(item,index) in newsList" :key="index">
				
				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px;'" @scrolltolower="loadmore(index)">
					<template v-if="item.list.length>0">
						<!-- 列表 -->
						<block v-for="(item2,index2) in item.list" :key="index2">
							<user-list :item="item2" :index="index2">
								
							</user-list>
	
						</block>
						<!-- 上拉加載 -->
						<load-more v-if="item.list.length>10"
						:loadmore="item.loadmore"></load-more>
					</template>
					<template v-else>
						<!-- 無數據渲染頁面 -->
						<no-thing>來了啊老弟</no-thing>
						
					</template>
						
						
						
				</scroll-view>
				
			</swiper-item>
			
		</swiper>
		
	</view>
</template>

<script>
	
	const demo = [{
		avatar:"/static/default.jpg",
		username:"昵稱",
		sex:0, // 0未知,1女性,2男性
		age:30,
		isFollow:false
	}
	];
	
	import loadMore from '@/components/common/load-more.vue'
	import userList from '@/components/user-list/user-list.vue'
	export default {
		components:{
			loadMore,
			userList
		},
		data() {
			return {
				tabIndex:0,
				tabBars:[{
					name:"互關",
					num:0,
					key:"friends"
				},{
					name:"關注",
					num:0,
					key:"follows"
				},{
					name:"粉絲",
					num:0,
					key:"fens"
				}],
				scrollH:600,
				newsList:[]
			}
		},
		
		onLoad() {
			uni.getSystemInfo({
				success:res=>{
								// 可用窗口高度(屏幕高度-導航欄高度-底部欄高度。) -  選項卡高度
					this.scrollH = res.windowHeight - uni.upx2px(101)
					console.log(this.scrollH)
					
				}
			})
			// 根據選項生成列表
			this.getData()
		},
		// 監聽點擊輸入框事件
		onNavigationBarSearchInputClicked() {
			uni.navigateTo({
				url: '../search/search?type=user',
			});
		},
		methods: {
			changeTab(index){
				this.tabIndex = index
				
			},
			// 監聽選項內容滑動
			onChangeTab(e){
				this.changeTab(e.detail.current)
				if(!this.newsList[e.detail.current].firstLoad){
					this.getList()
				}
			},
			// 上拉加載更多
			loadmore(index){
				// 拿到當前列表
				let item = this.newsList[index]
				// 修改當前加載狀態
				item.loadmore = '加載中。。。'
				// 模擬數據請求
				setTimeout(()=>{
					// 加載數據
								// ... 相當於取出來當前對象可以遍歷出來的內容放到了當前對象里面。
								// 這個可以粗糙的理解為把合並了兩個一摸一樣的列表,列表里面原來的內容*2了 
					item.list = [...item.list,...item.list]
					item.loadmore = '上拉加載更多'
				},2000)
			},
			// 制作列表+上拉加載數據初始值
			getData(){
				var arr=[]
				for (let i = 0; i < this.tabBars.length;i++ ){
					let obj ={
						loadmore:"上拉加載更多",
						list:[],
						page:1,
						fristLoad:false
					}
					// if (i < 2) {
					// 	obj.list = demo
					// }
					arr.push(obj)
				}
				this.newsList = arr
				this.getList()
			},
			getList(){
				let index = this.tabIndex
				// let id = this.tabBars[index].id
				let page = this.newsList[index].page
				let isrefresh = page === 1
				this.$H.get('/'+this.tabBars[index].key+'/'+page,{},{
					token:true,
					noExToken:true,
					// native:true
				})
				.then(res=>{
					console.log(res);
					let list = res.list.map(v=>{
						return {
							id:v.id,
							avatar:v.userpic,
							username:v.username,
							sex:v.userinfo.sex,
							age:v.userinfo.age,
							isFollow:index !== 2
						}
					})
					
					
					this.newsList[index].list = isrefresh ? list : [...this.newsList[index].list,...list];
					
					this.newsList[index].loadmore  = list.length < 10 ? '沒有更多了' : '上拉加載更多';
					
					if (isrefresh) {
						this.newsList[index].firstLoad = true
					}
				}).catch(err=>{
					if(!isrefresh){
						this.newsList[index].page--;
					}
				})
			},
		}
	}
</script>

<style>

</style>

搜索用戶功能實現(略)

<template>
	<view>
		<template v-if="searchList.length === 0">
			<!-- 搜索歷史 -->
			<view class="py-2 font-md px-2">搜索歷史</view>
			<view class="flex flex-wrap">
				<view class="border rounded font mx-2 my-1 px-2" 
				v-for="(item,index) in historyList" :key="index"
				hover-class="bg-light"
				@click="clickSearchHistory(item)">{{item}}</view>
			</view>
		</template>
		<template v-else>
			<!-- 數據列表 -->
			<block v-for="(item,index) in searchList" :key="index">
				<template v-if="type ==='post'">
					<!-- 帖子 -->
					<common-list :item="item" :index="index"></common-list>
				</template>
				<template v-else-if="type === 'topic'">
					<!-- 話題 -->
					<topic-list :item="item" :index="index"></topic-list>
				</template>
				<template v-else>
					<!-- 用戶 -->
					<user-list :item="item" :index="index"></user-list>
				</template>
			</block>
			<!-- 上拉加載 -->
			<load-more :loadmore="loadmore"></load-more>
		</template>
		
	</view>
</template>

<script>
	import commonList from '@/components/common/common-list.vue';
	import topicList from '@/components/news/topic-list.vue';
	import userList from '@/components/user-list/user-list.vue';
	import loadMore from '@/components/common/load-more.vue';
	export default {
		components: {
			commonList,
			topicList,
			userList,
			loadMore
			
		},
		data() {
			return {
				searchText:"",
				historyList:[],
				// 搜索結果
				searchList:[],
				// 當前搜索類型
				type:"post",
				page:1,
				loadmore:"上拉加載更多"
			}
		},
		// 監聽導航輸入
		onNavigationBarSearchInputChanged(e){
			this.searchText = e.text
			// console.log(e.text)
		},
		// 監聽點擊導航搜索按鈕
		onNavigationBarButtonTap(e) {
			if (e.index === 0) {
				this.searchEvent()
			}
		},
		// 監聽下拉刷新
		onPullDownRefresh() {
			if(this.searchText == ''){
				return uni.stopPullDownRefresh()
			}
			// 請求數據
			this.getData(true,()=>{
				uni.stopPullDownRefresh()
			})
		},
		// 監聽上拉加載更多
		onReachBottom() {
			if(this.loadmore != '上拉加載更多'){
				return;
			}
			this.loadmore = '加載中...'
			this.getData(false)
		},
		onUnload() {
			if(this.type === 'post'){
				uni.$off('updateFollowOrSupport',this.listionFollowOrSupport)
			}
		},
		onLoad(e) {
			if (e.type) {
				this.type = e.type
			}
			let pageTitle = '帖子'
			switch (this.type){
				case 'post':
				pageTitle = '帖子'
				uni.$on('updateFollowOrSupport',this.listionFollowOrSupport)
					break;
				case 'topic':
				pageTitle = '話題'
					break;
				case 'user':
				pageTitle = '用戶'
					break;
			}
			
			// 碰到這種找不到元素的情況,直接來個nextTick等所有都渲染完了就不會出問題。
			this.$nextTick(function(){
				// 修改搜索占位
				// #ifdef APP-PLUS
				let currentWebview = this.$mp.page.$getAppWebview();
				let tn = currentWebview.getStyle().titleNView; 
				tn.searchInput.placeholder = '搜索'+pageTitle; 
				currentWebview.setStyle({
					titleNView: tn  
				})
				// #endif
			})
			
			// 取出搜索歷史
			let list = uni.getStorageSync(this.type+'historyList')
			if (list) {
				this.historyList = JSON.parse(list)
			}
		},
		methods: {
			// 
			listionFollowOrSupport(e){
					switch (e.type){
						case 'follow': // 關注
						this.follow(e.data.user_id)
							break;
						default:
							break;
					}
				},
			// 關注
			follow(user_id){
				// 找到當前作者的所有列表
				this.searchList.forEach((item)=>{
					if(item.user_id === user_id){
						item.isFollow = true
					}
				})
				uni.showToast({ title: '關注成功' })
			},
			// 點擊搜索歷史
			clickSearchHistory(text){
				this.searchText = text
				this.searchEvent()
			},
			// 搜索事件
			searchEvent(){
				// 收起鍵盤
				uni.hideKeyboard()
				
				// 添加搜索歷史
				let index = this.historyList.findIndex(v => v===this.searchText)
				if (index!=-1){
					this.$U.__toFirst(this.historyList,index)
				}else{
					// unshift 在原來數據的基礎上添加第一個元素。
					this.historyList.unshift(this.searchText)
				}
				// 添加到本地緩存
				uni.setStorageSync(this.type+'historyList',JSON.stringify(this.historyList))
				
				// 請求搜索到的數據
				this.getData()
			},
			
			// 請求數據
			getData(isrefresh=true,callback=false){
				// isrefresh : 是否從第一頁加載?
				// 顯示loading狀態
				uni.showLoading({
					title: '加載中...',
					mask: false
				})
				this.page = isrefresh ? 1 : this.page+1
				// 請求搜索
				this.$H.post('/search/'+this.type,{
					keyword:this.searchText,
					page:this.page
				}).then(res=>{
					console.log()
					let list = []
					switch (this.type){
						case 'post':
							list = res.list.map(v => {
								return this.$U.formatCommonList(v)
							})
							break;
						case 'topic':
							list = res.list.map(v=>{
								return {
									id:v.id,
									cover:v.titlepic,
									title:v.title,
									desc:v.desc,
									today_count:v.todaypost_count,
									news_count:v.post_count
								}
							})
							break;
						case 'user':
						list = res.list.map(v=>{
							return {
								id:v.id,
								avatar:v.userpic,
								username:v.username,
								sex:v.userinfo.sex,
								age:v.userinfo.age,
								isFollow:false
								}
							})
							break;
					}
					// 渲染頁面
					this.searchList = isrefresh ? list : [...this.searchList, ...list]
					// 加載情況
					this.loadmore = list.length < 10 ? '沒有更多了':'上拉加載更多'
					
					// 關掉普通加載中動畫
					uni.hideLoading()
					// 給下拉刷新使用的,也是一種思路
					if (typeof callback === 'function'){
						callback()
					}
				}).catch(err=>{
					this.page--
					// 關掉普通加載中動畫
					uni.hideLoading()
					// 給下拉刷新使用的,也是一種思路
					if (typeof callback === 'function'){
						callback()
					}
				})
			}
		}
	}
</script>

<style>

</style>

十三 個人空間實現

效果:

自己訪問的時候

image-20200512211859593

別人訪問的時候

image-20200512212015189

有聊天和加入黑名單選項

image-20200512212208140

可以看發了什么帖子

image-20200512212317037

思路(略):

都是正常的業務邏輯

代碼

<template>
	<view>
		<!-- 頭部 -->
		<view class="flex align-center p-3 border-bottom border-light-secondary">
			<image :src="userinfo.userpic" 
			style="width: 180rpx;height: 180rpx;"
			class="rounded-circle"></image>
			<view class="pl-3 flex flex-column flex-1">
				<view class="flex align-center">
					<view class="flex-1 flex flex-column align-center justify-center" v-for="(item,index) in counts" :key="index">
						<text class="font-lg font-weight-bold">{{item.num|formatNum}}</text>
						<text class="font text-muted">{{item.name}}</text>
					</view>
				</view>
				<view class="flex justify-center align-center">
					
					<button v-if="user_id == user.id"
					 type="default" size="mini"
					style="width: 400rpx;" @click="openUserInfo">
						編輯資料
					</button>
					
					<button v-else
					type="default" size="mini" 
					:class="userinfo.isFollow ? 'bg-light text-dark' : 'bg-main'"
					style="width: 400rpx;" @click="doFollow">
						{{userinfo.isFollow ? '已關注' : '關注'}}
					</button>

				</view>
			</view>
		</view>
		
		<!-- tab -->
		<view class="flex align-center" style="height: 100rpx;">
			<view class="flex-1 flex align-center justify-center"
			v-for="(item,index) in tabBars" :key="index"
			:class="index === tabIndex ? 'font-lg font-weight-bold text-main':'font-md'"
			@click="changeTab(index)">
			{{item.name}}</view>
		</view>
		
		<template v-if="tabIndex === 0">
			<view class="animated fast fadeIn">
				<view class="p-3 border-bottom">
					<view class="font-md">賬號信息</view>
					<view class="font">賬號年齡:{{userinfo.regtime}}</view>
					<view class="font">賬號id:{{user_id}}</view>
				</view>
				<view class="p-3 border-bottom">
					<view class="font-md">個人信息</view>
					<view class="font">星座:{{userinfo.birthday}}</view>
					<view class="font">職業:{{userinfo.job}}</view>
					<view class="font">故鄉:{{userinfo.path}}</view>
					<view class="font">情感:{{userinfo.qg}}</view>
				</view>
			</view>
		</template>
		<template v-else>
			<view class="animated fast fadeIn">
				<common-list v-for="(item,index) in list" :key="index" :item="item" :index="index" @follow="follow" @doSupport="doSupport"></common-list>
				<divider></divider>
				<load-more :loadmore="loadmore"></load-more>
			</view>
		</template>
		
		
		
		<!-- 彈出層 -->
		<uni-popup ref="popup" type="top">
			<view class="flex align-center justify-center font-md border-bottom py-2 bg-light" hover-class="bg-main text-white" @click="doBlack">
				<text class="iconfont icon-sousuo mr-2"></text> 
				{{userinfo.isblack ? '移出黑名單' : '加入黑名單'}}
			</view>
			<view v-if="!userinfo.isblack" class="flex align-center justify-center font-md py-2 bg-light " hover-class="bg-main text-white">
				<text class="iconfont icon-shanchu mr-2"></text> 聊天
			</view>
		</uni-popup>
		
		
	</view>
</template>

<script>
	const emotionArray = ['保密', '未婚', '已婚']
	import commonList from '@/components/common/common-list.vue';
	import loadMore from '@/components/common/load-more.vue';
	import uniPopup from '@/components/uni-ui/uni-popup/uni-popup.vue';
	import $T from '@/common/time.js';
	import { mapState } from 'vuex'
	export default {
		components: {
			commonList,
			loadMore,
			uniPopup
		},
		data() {
			return {
				user_id:0,
				userinfo:{
					userpic:"/static/default.jpg",
					username:"",
					sex:0,
					age:20,
					isFollow:false,
					regtime:"",
					birthday:"",
					job:"",
					path:"",
					qg:""
				},
				counts:[{
					name:"帖子",
					num:0
				},{
					name:"關注",
					num:0
				},{
					name:"粉絲",
					num:0
				}],
				tabIndex:0,
				tabBars:[{
					name:"主頁",
				},{
					name:"帖子",
					list:[],
					// 1.上拉加載更多  2.加載中... 3.沒有更多了
					loadmore:"上拉加載更多",
					page:1
				},{
					name:"動態",
					list:[],
					// 1.上拉加載更多  2.加載中... 3.沒有更多了
					loadmore:"上拉加載更多",
					page:1
				}],
			}
		},
		onNavigationBarButtonTap() {
			if(this.user_id == this.user.id){
				return uni.navigateTo({
					url: '../user-set/user-set',
				});
			}
			this.$refs.popup.open()
		},
		computed: {
			...mapState({
				user:state=>state.user
			}),
			list() {
				return this.tabBars[this.tabIndex].list 
			},
			loadmore(){
				return this.tabBars[this.tabIndex].loadmore
			}
		},
		filters: {
			formatNum(value) {
				return value > 99 ? '99+' : value;
			}
		},
		onLoad(e) {
			if(!e.user_id){
				return uni.showToast({
					title: '非法參數',
					icon: 'none'
				});
			}
			this.user_id = e.user_id
			// 加載用戶個人信息
			this.getUserInfo()
			// 獲取用戶相關數據
			this.getCounts()
			// 監聽關注和頂踩操作
			uni.$on('updateFollowOrSupport',(e)=>{
				switch (e.type){
					case 'follow': // 關注
					this.follow(e.data.user_id)
						break;
					case 'support': // 頂踩
					this.doSupport(e.data)
						break;
				}
			})
			// 監聽評論數變化
			uni.$on('updateCommentsCount',({id,count})=>{
				this.tabBars.forEach(tab=>{
					if(tab.list){
						tab.list.forEach((item)=>{
							if(item.id === id){
								item.comment_count = count
							}
						})
					}
				})
			})
		},
		onUnload() {
			uni.$off('updateFollowOrSupport',(e)=>{})
			uni.$off('updateCommentsCount',(e)=>{})
		},
		methods: {
			// 獲取用戶相關數據
			getCounts(){
				this.$H.get('/user/getcounts/'+this.user_id).then(res=>{
					this.counts[0].num = res.post_count
					this.counts[1].num = res.withfollow_count
					this.counts[2].num = res.withfen_count
				})
			},
			// 獲取用戶個人信息
			getUserInfo(){
				this.$H.post('/getuserinfo',{
					user_id:this.user_id
				},{
					token:true,
					notoast:true
				}).then(res=>{
					this.userinfo = {
						userpic:res.userpic,
						username:res.username,
						sex:res.userinfo.sex,
						age:res.userinfo.age,
						isFollow:res.fens.length > 0,
						isblack:res.blacklist.length > 0,
						regtime:$T.dateFormat(new Date(res.create_time * 1000), '{Y}-{MM}-{DD}'),
						birthday:$T.getHoroscope(res.userinfo.birthday),
						job:res.userinfo.job ? res.userinfo.job : '無',
						path:res.userinfo.path ? res.userinfo.path : '無',
						qg:emotionArray[res.userinfo.qg],
					}
					uni.setNavigationBarTitle({
						title:this.userinfo.username
					})
				})
			},
			changeTab(index){
				this.tabIndex = index
				this.getList()
			},
			// 關注
			follow(user_id){
				// 找到當前作者的所有列表
				this.tabBars.forEach(tab=>{
					if(tab.list){
						tab.list.forEach((item)=>{
							if(item.user_id === user_id){
								item.isFollow = true
							}
						})
					}
				})
				uni.showToast({ title: '關注成功' })
			},
			// 頂踩操作
			doSupport(e){
				// 拿到當前的選項卡對應的list
				this.tabBars[this.tabIndex].list.forEach(item=>{
					if(item.id === e.id){
						// 之前沒有操作過
						if (item.support.type === '') {
							item.support[e.type+'_count']++
						} else if (item.support.type ==='support' && e.type === 'unsupport') {
							// 頂 - 1
							item.support.support_count--;
							// 踩 + 1
							item.support.unsupport_count++;
						} else if(item.support.type ==='unsupport' && e.type === 'support'){ 					// 之前踩了
							// 頂 + 1
							item.support.support_count++;
							// 踩 - 1
							item.support.unsupport_count--;
						}
						item.support.type = e.type
					}
				})
				let msg = e.type === 'support' ? '頂' : '踩'
				uni.showToast({ title: msg + '成功' });
			},
			// 獲取文章列表
			getList(){
				let index = this.tabIndex
				if(index === 0) return;
				let page = this.tabBars[index].page
				let isrefresh = page === 1
				this.$H.get('/user/'+this.user_id+'/post/'+page)
				.then(res=>{
					let list = res.list.map(v=>{
						return this.$U.formatCommonList(v)
					})
					this.tabBars[index].list = isrefresh ? [...list] : [...this.tabBars[index].list,...list]
					this.tabBars[index].loadmore = list.length < 10 ? '沒有更多了' : '上拉加載更多'
				}).catch(err=>{
					if(!isrefresh){
						this.tabBars[index].page--
					}
				})
			},
			// 關注/取消關注
			doFollow(){
				this.checkAuth(()=>{
					let url = this.userinfo.isFollow ? '/unfollow' : '/follow'
					let msg = this.userinfo.isFollow ? '取消關注' : '關注'
					this.$H.post(url,{
						follow_id:this.user_id
					},{
						token:true
					}).then(res=>{
						this.userinfo.isFollow = !this.userinfo.isFollow
						uni.showToast({
							title: msg+'成功',
							icon: 'none'
						});
						uni.$emit('updateIndex')
						this.getList()
					})
				})
			},
			// 進入編輯資料
			openUserInfo(){
				uni.navigateTo({
					url: '../user-userinfo/user-userinfo',
				});
			},
			// 加入/移出黑名單
			doBlack(){
				this.checkAuth(()=>{
					let url = this.userinfo.isblack ? '/removeblack':'/addblack'
					let msg = this.userinfo.isblack ? '移出黑名單' : '加入黑名單'
					uni.showModal({
						content: '是否要'+msg,
						success: (res)=> {
							if (res.confirm) {
								this.$H.post(url,{
									id:this.user_id
								},{
									token:true
								}).then(res=>{
									this.userinfo.isblack = !this.userinfo.isblack
									uni.showToast({
										title: msg+'成功',
										icon: 'none'
									});
								})
							}
						}
					});
					
				})
			}
		}
	}
</script>

<style>

</style>

十四 各個主要數據頁面監聽刷新事件

以index.vue為例子

onLoad() {
			uni.getSystemInfo({
				success:res=>{
								// 可用窗口高度(屏幕高度-導航欄高度-底部欄高度。) -  選項卡高度
					this.scrollH = res.windowHeight - uni.upx2px(101)
					// console.log(this.scrollH)
				}
			})
			// 根據選項生成列表
			this.getData()
			
			// 監聽點踩操作進行數據更新。
			uni.$on('updateFollowOrSupport' ,this.listionFollowOrSupport)
			// 監聽評論數進行數據更新。
			uni.$on('updateCommentsCount' ,this.updateCommentsCountBack)
			// 監聽刷新首頁數據
			uni.$on('updateIndex',this.getData)
			
		},
		onUnload() {
			uni.$off('updateFollowOrSupport',this.listionFollowOrSupport)
			uni.$off('updateCommentsCount',this.updateCommentsCountBack)
			uni.$off('updateIndex',this.getData)
		},

修改vuex倉庫store/index.js

設置登入登出的時候主要頁面刷新數據。

// 登錄
		login(state,user){
			// 更改state中的變量要在這里更改。
			state.loginStatus = true
			state.user = user
			// 登錄成功記錄一下token
			state.token = state.user.token
			// 永久存儲
			uni.setStorageSync('user',JSON.stringify(user));
			uni.$emit('updateIndex')
		},
// 退出登錄
		logout(state){
			state.loginStatus = false
			state.user = {}
			state.token = false
			uni.removeStorageSync('user')
			uni.$emit('updateIndex')
			
		},
      

十五 瀏覽歷史功能

思路

commonlis.vuet每次打開詳情頁面的時候都緩存到本地。

點擊瀏覽歷史,直接從本地緩存里面取出來記錄相關的數據進行渲染。

做一個清除瀏覽歷史的按鈕,原理就是直接把本地的緩存清除掉。

效果圖(略)

代碼

common-list.vue

openDetail(){
				if (this.isdetail) return;
				uni.navigateTo({
					url:'../../pages/detail/detail?detail='+JSON.stringify(this.item)
				})
				// 加入歷史記錄
				let list =  uni.getStorageSync('history')
				list = list ? JSON.parse(list) : []
				let index = list.findIndex(v=>v.id === this.item.id)
				if(index === -1){
					list.unshift(this.item)
					uni.setStorageSync('history',JSON.stringify(list))
				}
			}

History.vue

<template>
	<view>
		<common-list v-for="(item,index) in list" :key="index"
		:item="item" :index="index"></common-list>
		
		<no-thing v-if="list.length === 0"></no-thing>
	</view>
</template>

<script>
	import commonList from '@/components/common/common-list.vue';
	import noThing from '@/components/common/no-thing.vue';
	export default {
		components: {
			commonList
		},
		data() {
			return {
				list:[]
			}
		},
		onLoad() {
			// 取出歷史記錄
			let list =  uni.getStorageSync('history')
			if(list){
				this.list = JSON.parse(list)
			}
			// 監聽關注和頂踩操作
			uni.$on('updateFollowOrSupport',(e)=>{
				switch (e.type){
					case 'follow': // 關注
					this.follow(e.data.user_id)
						break;
					case 'support': // 頂踩
					this.doSupport(e.data)
						break;
				}
			})
			// 監聽評論數變化
			uni.$on('updateCommentsCount',({id,count})=>{
				this.list.forEach((item)=>{
					if(item.id === id){
						item.comment_count = count
					}
				})
			})
		},
		onUnload() {
			uni.$off('updateFollowOrSupport',(e)=>{})
			uni.$off('updateCommentsCount',(e)=>{})
		},
		onNavigationBarButtonTap() {
			uni.showModal({
				content: '是否要清除歷史記錄?',
				success: (res)=>{
					if (res.confirm) {
						uni.removeStorageSync('history')
						this.list = []
					}
				}
			});
		},
		methods: {
			// 關注
			follow(user_id){
				// 找到當前作者的所有列表
				this.list.forEach((item)=>{
					if(item.user_id === user_id){
						item.isFollow = true
					}
				})
				uni.showToast({ title: '關注成功' })
			},
			// 頂踩操作
			doSupport(e){
				// 拿到當前的選項卡對應的list
				this.list.forEach(item=>{
					if(item.id === e.id){
						// 之前沒有操作過
						if (item.support.type === '') {
							item.support[e.type+'_count']++
						} else if (item.support.type ==='support' && e.type === 'unsupport') {
							// 頂 - 1
							item.support.support_count--;
							// 踩 + 1
							item.support.unsupport_count++;
						} else if(item.support.type ==='unsupport' && e.type === 'support'){ 					// 之前踩了
							// 頂 + 1
							item.support.support_count++;
							// 踩 - 1
							item.support.unsupport_count--;
						}
						item.support.type = e.type
					}
				})
				let msg = e.type === 'support' ? '頂' : '踩'
				uni.showToast({ title: msg + '成功' });
			},
		}
	}
</script>

<style>

</style>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM