31 前端后端剩余粗糙筆記
一 綁定郵箱
<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()方法。
效果圖:
代碼:
<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提供的上傳圖片請求)
思路:
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);
})
}
})
},
四 修改資料功能實現(日期框,三級聯動地址)
效果圖:
關鍵點:
用了日期選框(調用系統原生的日期選擇器,並不友好)
用了一個開源的三級聯動(還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>
六 關注點贊點踩(多組件進行通訊,很有參考價值的業務邏輯。)
效果圖:
關注效果圖:
點贊點踩效果圖:
對各個頁面已經加載的數據點贊點踩同步就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
八 發布文章功能實現(選擇圖片直接上傳功能,可以關注草稿功能)
效果圖:
思路:
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>
十一 關注好友動態:
效果圖:
思路:
兩種請求數據的方式:
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>
十三 個人空間實現
效果:
自己訪問的時候
別人訪問的時候
有聊天和加入黑名單選項
可以看發了什么帖子
思路(略):
都是正常的業務邏輯
代碼
<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>