天天看點

第七天 黑馬十次方 吐槽清單與詳細頁、發吐槽與評論功能、問答頻道功能、掌握DataURL和阿裡雲OSS第7章 網站前台-吐槽與問答1 吐槽清單與詳細頁2 發吐槽與吐槽評論3 問答頻道4 圖檔上傳

第7章 網站前台-吐槽與問答

學習目标:

**

完成吐槽清單與詳細頁

完成發吐槽與評論功能,掌握富文本編輯器的使用

完成問答頻道功能

掌握DataURL和阿裡雲OSS**

1 吐槽清單與詳細頁

1.1 吐槽清單頁

1.1.1 吐槽清單頁資料渲染

吐槽清單頁已經建構,我們現在來實作資料的渲染

(1)easyMock模拟資料

URL: spit/spit/search/{page}/{size}

Method: post

{ 
"code": 20000, 
"flag": true,
"message": "查詢成功", 
"data": { 
"total": "@integer(60, 100)", 
"rows|10": [{ 
"id": "@string", 
"content": "@cword(100,300)", 
"publishtime": "@datetime", 
"userid": "@string", 
"nickname": "小雅", 
"visits": "@integer(60, 100)", 
"thumbup": "@integer(60, 100)", 
"share": "@integer(60, 100)", 
"comment": "@integer(60, 100)", 
"state": "@string", 
"parentid": "@string" 
}] 
} 
}
           

(2)api目錄下建立spit.js

import request from '@/utils/request' 
const group_name = 'spit' 
const api_name = 'spit'
 export default { 
 search(page, size, searchMap) { 
 return request({
    url: `/${group_name}/${api_name}/search/${page}/${size}`,
    method: 'post',
    data: searchMap 
    }) 
    } 
    }
           

(3)修改pages/spit/index.vue

<template> 
<div> 
<div class="wrapper tag‐item"> 
<div class="fl left‐list"> 
<div class="tc‐data‐list"> 
<div class="tc‐list"> 
<ul class="detail‐list"> 
<li class="qa‐item" v‐for="(item,index) in items" :key="index"> 
<div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum"><a href="#" class="zan"><i class="fa fa‐ thumbs‐up " aria‐hidden="true"></i></a></p> 
<p class="zannum"> {{item.thumbup}} </p> 
</div> 
<div class="border answer"> 
<a href="#" class="star"><i class="fa fa‐star‐o" aria‐ hidden="true"></i></a> </div> 
</div> 
</div> 
<div class="info"> 
<p class="text"> <a href="~/assets/spit‐detail.html" target="_blank"> {{item.content}} </a> </p> 
<div class="other"> 
<div class="fl date"> 
<span>{{item.publishtime}}</span> 
</div> 
<div class="fr remark"> 
<a href="#" data‐toggle="modal" data‐target="#shareModal" class="share"><i class="fa fa‐share‐alt" aria‐hidden="true"></i> 分享</a> 
<a href="#" data‐toggle="modal" data‐target="#remarkModal" class="comment"><i class="fa fa‐commenting" aria‐hidden="true"></i> 回 複</a> 
</div> 
</div> 
</div> 
<div class="clearfix"></div> </li> 
</ul> 
<div class="modal fade" id="shareModal" tabindex="‐1"role="dialog" aria‐labelledby="myModalLabel"> 
<div class="modal‐dialog" role="document"> 
<div class="modal‐content"> 
<div class="modal‐header"> 
<button type="button" class="close" data‐dismiss="modal" aria‐ label="Close"><span aria‐hidden="true">&times;</span></button> 
<h4 class="modal‐title" id="myModalLabel">分享到</h4> 
</div> 
<div class="modal‐body" style="overflow:hidden"> 
<div class="jiathis_style_32x32"> 
<a class="jiathis_button_qzone"></a> 
<a class="jiathis_button_tsina"></a> 
<a class="jiathis_button_weixin"></a> 
<a class="jiathis_button_cqq"></a> 
</div> 
</div> 
</div> 
</div> 
</div> 
<div class="modal fade" id="remarkModal" tabindex="‐1" role="dialog" aria‐labelledby="myModalLabel"> 
<div class="modal‐dialog" role="document"> 
<div class="modal‐content"> 
<div class="modal‐header"> 
<button type="button" class="close" data‐dismiss="modal" aria‐ label="Close"><span aria‐hidden="true">&times;</span></button> 
<h4 class="modal‐title" id="myModalLabel">發表評論</h4> </div> <div class="modal‐body"> <div class="comment"> 
<span class="who"><img src="~/assets/img/asset‐photo.png" /> 匿名評論</span>: 今天入職騰訊,産品崗,普通非985211大學,上家是不到五十人創業小 公司!16年畢業!找内推騰訊給的面試機會,五輪面試!可能是我把運氣攢一起了! 
</div> 
<div class="form"> 
<textarea class="form‐control" rows="5" placeholder="匿名評 論"></textarea> <div class="remark"> 
<button class="sui‐btn btn‐info">發表</button> 
</div> 
</div>
</div> 
</div> 
</div> 
</div> 
</div> 
</div> 
</div> 
<div class="fl right‐tag"> 
<div class="block‐btn"> 
<p>來個匿名吐槽,發洩一下你心中的怒火吧!</p> 
<a class="sui‐btn btn‐block btn‐share" href="~/assets/spit‐ submit.html" target="_blank">發吐槽</a> 
</div> 
</div> 
<div class="clearfix"></div> 
</div> 
</div> 
</template> 
<script> 
import '~/assets/css/page‐sj‐spit‐index.css' 
import spitApi from '@/api/spit' 
export default { 
asyncData(){ 
return spitApi.search(1,10, {state:'1'} ).then( res=> { 
return {items:res.data.data.rows}
 }) 
 } 
 }
 </script>
           

1.1.2 吐槽清單瀑布流

修改頁面pages/spit/index.vue

修改pages/spit/index.vue ,添加pageNo用于記錄頁碼 增加方法

data(){ 
return { 
pageNo: 1 
} 
},
methods:{ 
loadMore(){ 
this.pageNo++ spitApi.search( this.pageNo,10,{state:'1'} ).then( res=>{ this.items=this.items.concat( res.data.data.rows )
 }) 
 } 
 }
           

1.2 吐槽詳情頁

1.2.1 建構吐槽詳情頁

(1)根據spit-detail.html建立pages/spit/_id.vue ,内容略

(2)修改pages/spit/index.vue 頁面連結

1.2.2 吐槽詳情頁資料渲染

(1)easyMock模拟資料

URL: spit/spit/{id}

Methos: GET

{ 
"code": 20000, 
"flag": true, 
"message": "@string", 
"data": { 
"id": "@string", 
"nikename": "小雅", 
"content": "@cword(100,300)", 
"publishtime": "@datetime", 
"thumbup": "@integer(60, 100)", 
"share": "@integer(60, 100)", 
"comment": "@integer(60, 100)" 
} 
}
           

URL: spit/spit/commentlist/{id}

Method: GET

{ 
"code": 20000, 
"flag": true, 
"message": "@string", 
"data|10": [{ 
"id": "@string", 
"content": "我要評論我要評論我要評論我要評論我要評論我要評論", 
"nikename": "小雅", 
"publishtime": "@datetime",
 "thumbup": "@integer(60, 100)" 
 }] 
 }
           

(2)修改api/spit.js

findById(id){
 return request({ 
 url: `/${api_group}/${api_name}/${id}`,
  method: 'get' 
  }) 
  },
  commentlist(id){
   return request({ 
   url: `/${api_group}/${api_name}/commentlist/${id}`, 
   method: 'get'
    })
     }
           

(3)修改pages/spit/_id.vue

<template> 
<div class="wrapper tc‐detail"> 
<div class="fl left‐list"> 
<div class="tc‐detail"> 
<!‐‐ 标題區 ‐‐> 
<div class="detail‐tit"> 
<div class="detail‐author"> 
<a href="javascript:;">{{pojo.nickname}}</a> 釋出 
</div> 
<div class="detail‐content"> 
<p>{{pojo.content}}</p> 
</div> 
<div class="detail‐tool"> 
<ul> 
<li><span class="star"><i class="fa fa‐thumbs‐o‐up" aria‐ hidden="true"></i> {{pojo.thumbup}}</span></li> 
<li><a href="#" data‐toggle="modal" data‐target="#shareModal"><i class="fa fa‐share‐alt" aria‐hidden="true"></i> {{pojo.share}}</a></li> 
<li><a data‐toggle="modal" data‐target="#remarkModal"><i class="fa fa‐commenting" aria‐hidden="true"></i> {{pojo.comment}}</a> </li> 
</ul> 
</div> 
</div> 
<!‐‐ 評論區 ‐‐> 
<div class="comment‐area"> 
<div class="comment‐tit"> 
<span>評論</span> 
</div> 
<ul class="comment‐list"> 
<li v‐for="(item,index) in commentlist" :key="index"> 
<div class="item‐photo"> 
<img src="~/assets/img/widget‐widget‐photo.png" alt="" /> 
</div> 
<div class="item‐content"> 
<p class="author"><a href="javascript:;">{{item.nickname}}</a> 釋出</p> 
<p class="content">{{item.content}}</p> 
</div>
<div class="item‐thumb"> 
<div> 
<i class="fa fa‐thumbs‐o‐up" aria‐hidden="true"></i> {{item.thumbup}} 
</div> 
</div> </li> 
</ul> 
</div> 
</div> 
</div> 
<div class="fl right‐tag"> 
<div class="block‐btn"> <p>來個匿名吐槽,發洩一下你心中的怒火吧!</p> 
<a class="sui‐btn btn‐block btn‐share" href="~/assets/spit‐ submit.html" target="_blank">發吐槽</a> 
</div> 
</div> 
<div class="clearfix"></div> 
</div> 
</template> 
<script> 
import '~/assets/css/page‐sj‐spit‐detail.css' 
import spitApi from '@/api/spit' 
import axios from 'axios' 
export default { 
asyncData({params}){ 
return axios.all( [ spitApi.findById(params.id),spitApi.commentlist(params.id) ] ).then( axios.spread( function( pojo,commentlist ){ 
return { 
pojo: pojo.data.data, 
commentlist: commentlist.data.data 
} 
}) 
) 
} 
}
</script>
           

1.3 吐槽點贊

1.3.1 基本功能

(1)easyMock模拟資料

URL: spit/spit/thumbup/{id}

Method: put

(2)api/spit.js 增加方法

thumbup(id) 
{ 
return request({ 
url: `/${api_group}/${api_name}/thumbup/${id}`, 
method: 'put' 
}) 
}
           

(3)修改pages/spit/index.vue

methods: { 
thumbup(index){ 
spitApi.thumbup(this.items[index].id).then( res=>{ 
if(res.data.flag){
 this.items[index].thumbup++ 
 } 
 }) 
 } 
 }
           

(4)點贊調用

1.3.2 樣式處理

實作點贊後,大拇指圖示變色。樣式表已經寫好,在li 的樣式上加上color 即可

(1)修改pages/spit/index.vue 的代碼部分

import '~/assets/css/page‐sj‐spit‐index.css' 
import spitApi from '@/api/spit' 
export default { 
asyncData(){ 
return spitApi.search(1,10, {state:'1'} ).then( res=> { 
let tmp= res.data.data.rows.map( item=>{ 
return { 
...item, 
zan: '' 
} 
})
return {items:tmp} 
}) 
},
data(){ 
return { 
pageNo: 1 
} 
},
methods:{ 
loadMore(){ 
this.pageNo++ 
spitApi.search( this.pageNo,10,{state:'1'} ).then( res=>{ 
let tmp= res.data.data.rows.map( item=>{ 
return { 
...item,
 zan: '' 
 }
  }) 
  this.items=this.items.concat( tmp ) 
  }) 
  },
  thumbup(index){ 
  this.items[index].zan='color' 
  spitApi.thumbup(this.items[index].id).then( res=>{ 
  if(res.data.flag){ 
  this.items[index].thumbup++
   } 
   })
    }
    }
   }
           

(2)修改pages/spit/index.vue的html部分

<a href="#" class="zan"> 
<i :class="'fa fa‐thumbs‐up '+item.zan" aria‐hidden="true"></i> 
</a>
           

1.3.3 判斷是否登陸

要求:點贊必須要在使用者登陸的情況下執行,非登陸狀态下不能點贊。并且不可重複點 贊

導入getUser

修改thumbup(點贊)方法

thumbup(index){ 
if(getUser().name===undefined){ 
this.$message({ 
message:'必須登陸才可以點贊哦~', 
type:"warning" })
return }
if( this.items[index].zan==='color'){
 this.$message({ 
 message:'不可以重複點贊哦~', 
 type:"warning" 
 })
 return
 }
 this.items[index].zan='color' 
 spitApi.thumbup(this.items[index].id).then( res=>{ 
 if(res.data.flag){ 
 this.items[index].thumbup++ 
 } 
 }) 
 }
           

1.3.4 送出token

修改utils/request.js ,每次請求将token添加到header裡

import axios from 'axios' 
import {getUser} from '@/utils/auth' 
// 建立axios執行個體 
const service = axios.create({ 
baseURL: 'http://192.168.184.133:7300/mock/5af314a4c612520d0d7650c7', // api的base_url 
timeout: 30000, // 請求逾時時間 
headers: { 'Authorization': 'Bearer '+getUser().token } 
}) 
export default service
           

2 發吐槽與吐槽評論

2.1 發吐槽

2.1.1 建構頁面

我們這裡用到VUE常用的富文本編輯器vue-quill-editor

詳見文檔: https://www.npmjs.com/package/vue-quill-editor

(1)安裝vue-quill-editor

cnpm install vue‐quill‐editor ‐‐save
           

(2)plugins下建立nuxt-quill-plugin.js

import Vue from 'vue' 
import VueQuillEditor from 'vue‐quill‐editor/dist/ssr' Vue.use(VueQuillEditor)
           

(3)修改nuxt.config.js ,配置插件和樣式

plugins: [
 { src: '~plugins/nuxt‐quill‐plugin.js', ssr: false } 
 ],
 // some nuxt config... 
 css: [
  'quill/dist/quill.snow.css', 
  'quill/dist/quill.bubble.css',
   'quill/dist/quill.core.css' 
   ],
           

(4)pages/spit/submit.vue

<template> 
<div class="wrapper release‐tc"> 
<div class="release‐box"> 
<h3>釋出吐槽</h3> 
<div class="editor"> 
<div class="quill‐editor" 
:content="content" 
@change="onEditorChange($event)"
 @blur="onEditorBlur($event)" 
 @focus="onEditorFocus($event)" 
 @ready="onEditorReady($event)" v‐quill:myQuillEditor="editorOption"> 
 </div> 
 <div class="btns"> 
 <button class="sui‐btn btn‐danger btn‐release">釋出</button> 
 </div> 
 <div class="clearfix">
 </div> 
 </div> 
 </div> 
 <div class="clearfix">
 </div> 
 </div> 
 </template> 
 <script> 
 import '~/assets/css/page‐sj‐spit‐submit.css' 
 export default { 
 data () { 
 return { 
 content: '', 
 editorOption: {
  // some quill options 
  modules: { 
  toolbar: [ 
  [{ 'size': ['small', false, 'large'] }],
   ['bold', 'italic'],
    [{ 'list': 'ordered'}, { 'list': 'bullet' }], 
    ['link', 'image']
     ] 
     }
     } 
     } 
     },
     mounted() { 
     console.log('app init, my quill insrance object is:', this.myQuillEditor) 
     /*setTimeout(() => { this.content = 'i am changed' }, 3000)*/ },
     methods: { onEditorBlur(editor) { console.log('editor blur!', editor) },
     onEditorFocus(editor) { console.log('editor focus!', editor) },
     onEditorReady(editor) { console.log('editor ready!', editor) },
     onEditorChange({ editor, html, text }) { 
     console.log('editor change!', editor, html, text) 
     this.content = html 
     }
     }
     } 
     </script> 
     <style> 
     .quill‐editor { 
     min‐height: 200px; 
     max‐height: 400px; 
     overflow‐y: auto; 
     } 
     </style>
           

(5)修改pages/spit/index.vue 連結到此頁面

2.1.2 送出吐槽

(1)easyMock模拟資料

URL:spit/spit

Method: post

{ 
"code": 20000, 
"flag": true, 
"message": "執行成功"
 }
           

(2)修改api/spit.js ,增加送出吐槽的方法

save(pojo) { 
return request({ 
url: `/${group_name}/${api_name}`, 
method: 'post', 
data: pojo
}) 
}
           

(2)修改pages/spit/submit.vue 引入API

在methods增加方法

save(){ 
spitApi.save({ content:this.content } ).then(res=>{ 
this.$message({ 
message: res.data.message, 
type: (res.data.flag?'success':'error') 
})
if(res.data.flag){ 
this.$router.push('/spit') 
} 
}) 
}
           

$router.push()的作用是路由跳轉。

(3)釋出按鈕調用方法

2.2 吐槽評論

2.2.1 評論彈出框

我們這裡的評論彈出框使用elementUI的彈出框來實作

(1)修改pages/spit/_id.vue ,添加彈出框, 彈出框中放置富文本編輯器

<el‐dialog 
title="評論" 
:visible.sync="dialogVisible" 
width="40%" > 
<div class="quill‐editor" 
:content="content" 
@change="onEditorChange($event)" 
v‐quill:myQuillEditor="editorOption"> 
</div> <
span slot="footer" class="dialog‐footer"> 
<el‐button @click="dialogVisible = false">取 消</el‐button> 
<el‐button type="primary" @click="dialogVisible = false">确 定 
</el‐button> 
</span> 
</el‐dialog>
           

為富文本編輯框添加樣式:

<style> 
.quill‐editor {
 min‐height: 200px; 
 max‐height: 400px; 
 overflow‐y: auto;
  } 
</style>
           

(2)修改pages/spit/index.vue代碼部分

data(){
return { 
dialogVisible: false, 
content: '', 
editorOption: {
// some quill options
modules: { 
toolbar: [ 
[{ 'size': ['small', false, 'large'] }], 
['bold', 'italic'], 
[{ 'list': 'ordered'}, { 'list': 'bullet' }], 
['link', 'image'] 
] 
} 
} 
} 
},
methods:{ 
onEditorChange({ editor, html, text }) { 
console.log('editor change!', editor, html, text) 
this.content = html 
} 
}
           

(3)修改pages/spit/_id.vue 中的回複連結

在這裡插入代碼片
           

2.2.2 送出評論

修改pages/spit/_id.vue ,增加送出回複的方法

save(){ 
spitApi.save({ content:this.content,parentid: this.pojo.id } ).then(res=>{ this.$message({ 
message: res.data.message, 
type: (res.data.flag?'success':'error') 
})
if(res.data.flag){ 
this.dialogVisible=false 
spitApi.commentlist(this.pojo.id).then(res=>{ this.commentlist=res.data.data })
 } 
 }) 
 }
           

編輯送出按鈕

3 問答頻道

3.1 嵌套布局與标簽導航

3.1.1 嵌套布局

(1)建立pages/qa.vue

<template> 
<div> 
<div class="tab‐nav "> 
<div class="wrapper">
 <ul class="fl sui‐nav nav‐tabs navbar‐dark"> 
 <li class="active"><a href="#index" data‐toggle="tab">首頁</a> </li> 
 <li><a href="#php" data‐toggle="tab">Php</a></li>
 <li><a href="#js" data‐toggle="tab">Javascript </a></li> 
 <li><a href="#python" data‐toggle="tab">Python</a></li> 
 <li><a href="#java" data‐toggle="tab">Java</a></li> </ul> 
 <span class="fr more"><a href="./qa‐allTag.html" target="_blank">更多</a></span> 
 <div class="clearfix"></div> 
 </div> 
 </div> 
 <nuxt‐child/> 
 </div>
 </template> 
 <script> 
 import '~/assets/css/page‐sj‐qa‐logined.css' 
 export default { }
 </script>
           

(2)建立pages/qa/label/_label.vue

<template> 
<div class="wrapper qa‐content"> 
<div class="fl left‐list"> 
<div class="tab‐content"> 
<div id="index" class="tab‐pane active"> 
<div class="tab‐bottom‐line"> 
<ul class="sui‐nav nav‐tabs"> 
<li class="active"><a href="#new" data‐toggle="tab">最新回答</a> </li> 
<li><a href="#hot" data‐toggle="tab">熱門回答</a></li> 
<li><a href="#wait" data‐toggle="tab">等待回答</a></li> 
</ul> 
<div class="qa‐list"> 
<div class="tab‐content"> 
<div id="new" class="tab‐pane active"> 
<ul class="detail‐list"> 
<li class="qa‐item"> 
<div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum">12</p> 
<p>有用</p> 
</div> 
<div class="border answer"> 
<p class="ansnum">9</p> 
<p>回答</p> 
</div> 
</div> 
</div> 
<div class="fl info"> 
<div class="question"> 
<p class="author"><span class="name">luckness</span> <span>3</span>分鐘前回答</p> 
<p class="title"><a href="./qa‐detail.html" target="_blank">有關PHP初級進階的問題?</a></p> 
</div> <div class="other"> 
<ul class="fl sui‐tag"> 
<li>Php</li> 
<li>Javascript</li>
</ul> 
<div class="fr brower"> 
<p>浏覽量 50 | 2017‐07‐05 15:09 來自 <a href="#">畢鵬 </a> </p> 
</div> 
</div> 
</div> 
<div class="clearfix"></div> </li> 
<li class="qa‐item"> 
<div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum">12</p> 
<p>有用</p> 
</div> 
<div class="border answer"> 
<p class="ansnum">9</p> 
<p>回答</p> 
</div> 
</div> 
</div> 
<div class="fl info"> 
<div class="question"> 
<p class="author"><span class="name">牛奶糖</span> <span>3</span>分鐘前回答</p> <p class="title"><a href="./qa‐detail.html" target="_blank">springMVC的controller接收json資料失敗</a></p> 
</div> 
<div class="other"> 
<ul class="fl sui‐tag"> 
<li>Php</li> 
<li>Javascript</li> 
</ul> 
<div class="fr brower"> 
<p>浏覽量 50 | 2017‐07‐05 15:09 來自 <a href="#">畢鵬 </a> </p> 
</div> 
</div> 
</div>
<div class="clearfix"></div> </li> 
<li class="qa‐item">
<div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum">12</p> 
<p>有用</p> 
</div> 
<div class="border answer"> 
<p class="ansnum">9</p> 
<p>回答</p> 
</div> 
</div> 
</div> 
<div class="fl info"> 
<div class="question"> 
<p class="author"><span class="name">大白兔</span> <span>3</span>分鐘前回答</p> <p class="title"><a href="./qa‐detail.html" target="_blank">監聽器中timer查詢資料庫</a></p> 
</div> 
<div class="other"> 
<ul class="fl sui‐tag"> 
<li>Php</li> 
<li>Javascript</li> 
</ul> 
<div class="fr brower"> 
<p>浏覽量 50 | 2017‐07‐05 15:09 來自 <a href="#">畢鵬 </a> </p> 
</div> 
</div> 
</div> 
<div class="clearfix"></div> </li> 
<li class="qa‐item"> 
<div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum">34</p> 
<p>有用</p> 
</div> 
<div class="border answer"> 
<p class="ansnum">9</p> 
<p>回答</p>
</div> 
</div> 
</div> 
<div class="fl info"> 
<div class="question"> 
<p class="author"><span class="name">luckness</span> <span>3</span>分鐘前回答</p> 
<p class="title"><a href="./qa‐detail.html" target="_blank">伺服器上安裝了一個考試系統ASP.NET,安裝完成後通路不了,求助</a> </p> 
</div> 
<div class="other"> 
<ul class="fl sui‐tag"> 
<li>Php</li> 
<li>Javascript</li> 
</ul> 
<div class="fr brower"> 
<p>浏覽量 50 | 2017‐07‐05 15:09 來自 <a href="#">畢鵬 </a> </p> 
</div> 
</div> 
</div> 
<div class="clearfix"></div> </li> 
<li class="qa‐item"> 
<div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum">12</p> 
<p>有用</p> 
</div> 
<div class="border answer"> 
<p class="ansnum">9</p> 
<p>回答</p> 
</div> 
</div> 
</div> 
<div class="fl info"> 
<div class="question"> 
<p class="author"><span class="name">牛奶糖</span> <span>3</span>分鐘前回答</p> <p class="title"><a href="./qa‐detail.html"target="_blank">springMVC的controller接收json資料失敗</a></p> 
</div> 
<div class="other"> 
<ul class="fl sui‐tag"> <li>Php</li> 
<li>Javascript</li> 
</ul> 
<div class="fr brower"> 
<p>浏覽量 50 | 2017‐07‐05 15:09 來自 <a href="#">畢鵬 </a> </p> 
</div> 
</div> 
</div> 
<div class="clearfix"></div> </li> 
<li class="qa‐item"> 
<div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum">12</p> 
<p>有用</p> 
</div> 
<div class="border answer"> 
<p class="ansnum">9</p> 
<p>回答</p> </div> 
</div> 
</div> 
<div class="fl info"> 
<div class="question"> 
<p class="author"><span class="name">大白兔</span> <span>3</span>分鐘前回答</p> <p class="title"><a href="./qa‐detail.html" target="_blank">監聽器中timer查詢資料庫</a></p> 
</div> 
<div class="other"> 
<ul class="fl sui‐tag"> 
<li>Php</li> 
<li>Javascript</li> 
</ul> 
<div class="fr brower"> 
<p>浏覽量 50 | 2017‐07‐05 15:09 來自 <a href="#">畢鵬 </a></p> 
</div> 
</div> 
</div> 
<div class="clearfix"></div> </li> 
</ul> 
</div> 
<div id="hot" class="tab‐pane"> 
<p>熱門回答</p> 
</div> 
<div id="wait" class="tab‐pane"> 
<p>等待回答</p> 
</div> 
</div> 
</div> 
</div> 
</div> 
<div id="php" class="tab‐pane"> 
php 
</div> 
<div id="js" class="tab‐pane"> 
Javascript 
</div> 
<div id="python" class="tab‐pane">
 python
</div> 
<div id="java" class="tab‐pane"> 
java 
</div> 
</div> 
</div> 
<div class="fl right‐tag"> 
<div class="block‐btn"> 
<p>今天,有什麼好東西要和大家分享麼?</p> 
<a class="sui‐btn btn‐block btn‐share" href="./qa‐submit.html" target="_blank">釋出問題</a> 
</div> 
<div class="hot‐tags"> 
<div class="head"> 
<h3 class="title">熱門标簽</h3> 
</div>
<div class="tags"> 
<ul class="sui‐tag"> 
<li>Php</li> 
<li>Javascript</li> 
<li>Gif</li> 
<li>Java</li> 
<li>C#</li> 
<li>iOS</li> 
<li>C++</li> 
</ul> 
</div> 
</div> 
</div> 
<div class="clearfix"></div> 
</div> 
</template>
           

(3)建立pages/qa/index.vue

<template> 
<div></div> 
</template> 
<script> 
export default { 
created(){ this.$router.push('/qa/label/0') } }</script>
           

3.1.2 标簽導航

(1)easyMock模拟資料

URL: base/label/toplist

Method: GET

{ 
"flag": true, 
"code": 20000, 
"data": [{ 
"id": "1", "labelname": "JAVA" },{ "id": "2", "labelname": "PHP" },{ "id": "3", "labelname": "前端" },{ "id": "4", "labelname": "Python" } 
] 
}
           

(2)編寫标簽API 建立api/label.js

import request from '@/utils/request' import {getUser} from '@/utils/auth' const api_group = 'base' 
const api_name = 'label' 
export default { 
toplist() { 
return request({
url:`/${api_group}/${api_name}/toplist`, 
method: 'get' 
}) 
} 
}
           

(3)修改pages/qa.vue

<template> 
<div> 
<div class="tab‐nav "> 
<div class="wrapper"> 
<ul class="fl sui‐nav nav‐tabs navbar‐dark"> 
<router‐link tag="li" to="/qa" active‐class="active" exact > <a> 首頁</a></router‐link> 
<router‐link tag="li" :to="'/qa/label/'+item.id" active‐ class="active" v‐for="(item,index) in labelList" :key="index" > 
<a>{{item.labelname}} </a> 
</router‐link> 
</ul> 
<span class="fr more"><a href="./qa‐allTag.html" target="_blank">更多</a></span> 
<div class="clearfix">
</div> 
</div> 
</div> 
<nuxt‐child/> 
</div> 
</template> 
<script> import labelApi from '@/api/label' 
export default { 
asyncData ({ params, error}) { 
return labelApi.toplist().then((res) => { return {labelList: res.data.data } 
})
} 
}
</script>
           

(4)建立pages/qa/index.vue

<template> 
<div>
這裡是問答清單 
</div> 
</template>
           

3.2 問答清單

3.2.1 最新問答清單

(1)easy-mock模拟資料 URL:/qa/problem/newlist/{label}/{page}/{size} Method:GET

{ 
"code": "@integer(60, 100)", 
"flag": "@boolean", 
"message": "@string", 
"data": { 
"total": "@integer(60, 100)", "rows|10": [{ 
"id": "@integer(1, 1000)", 
"title": "@cword(20,30)", 
"content": "@string",
"createtime": "@datetime", "updatetime": "@datetime", 
"userid": "@integer(1, 1000)", "nickname": "小馬", 
"visits": "@integer(60, 100)", "thumbup": "@integer(60, 100)", "reply": "@integer(60, 100)", 
"solve": "@string", 
"replyname": "小牛", 
"replytime": "@datetime" 
}] 
} 
}
           

(2)API編寫 建立api/problem.js

import request from '@/utils/request' const group_name = 'qa' 
const api_name = 'problem' 
export default { list(type,label,page,size){
return request({ url:`/${group_name}/${api_name}/${type}/${label}/${page}/${size}`, method: 'get' 
}) 
} 
}
           

(3)修改pages/qa/label/_label.vue 腳本部分

import problemApi from '@/api/problem' import axios from 'axios' 
export default { 
asyncData({params}){ 
return axios.all([problemApi.list('newlist',params.label,1,10), problemApi.list('hotlist',params.label,1,10), problemApi.list('waitlist',params.label,1,10) ] ).then( axios.spread(function(newlist,hotlist,waitlist ){ return { newlist:newlist.data.data.rows, hotlist:hotlist.data.data.rows, waitlist:waitlist.data.data.rows } })) } }
           

(4)修改pages/qa/label/_label.vue 模闆部分

<ul class="detail‐list"> 
<li class="qa‐item" v‐for="(item,index) in newlist" :key="index"><div class="fl record"> 
<div class="number"> 
<div class="border useful"> 
<p class="usenum">{{item.thumbup}}</p> <p>有用</p> 
</div>
 <div class="border answer"> 
 <p class="ansnum">{{item.reply}}</p> <p>回答</p> 
 </div> 
 </div> 
 </div> 
 <div class="fl info"> 
 <div class="question"> 
 <p class="author"><span class="name">{{item.replyname}} </span><span>{{item.replytime}}</span>回答</p> 
 <p class="title"><a href="./qa‐detail.html" target="_blank">{{item.title}}</a></p> 
 </div> 
 <div class="other"> 
 <div class="fr brower"> 
 <p>浏覽量 {{item.visits}} | {{item.createtime}} 來自 <a href="#">{{item.nickname}} </a></p> 
 </div> 
 </div> 
 </div> 
 <div class="clearfix"></div> </li> </ul>
           

3.2.2 熱門回答和等待回答清單

(1)定義屬性type ,預設值為new

(2)修改頁籤

<ul class="sui‐nav nav‐tabs"> 
<li :class="type=='new'?'active':''"><a @click="type='new'">最新回 答</a></li> 
<li :class="type=='hot'?'active':''"><a @click="type='hot'">熱門回 答</a></li> 
<li :class="type=='wait'?'active':''"><a @click="type='wait'">等待 回答</a></li> </ul>
           

(3)修改div的樣式為動态擷取

最新回答清單

熱門回答清單

等待回答清單

(4)參照最新問答清單編寫熱門回答清單與等待回答清單内容

<li class="qa‐item" v‐for="(item,index) in hotlist" :key="index"> ..... 
<li class="qa‐item" v‐for="(item,index) in waitlist" :key="index">
           

3.2.3 問答清單瀑布流

(1)修改pages/qa/label/_label.vue模闆部分

(2)修改pages/qa/label/_label.vue腳本部分

import problemApi from '@/api/problem' import axios from 'axios' 
export default { 
asyncData({params}){
 return axios.all([
 problemApi.list('newlist',params.label,1,10), problemApi.list('hotlist',params.label,1,10), problemApi.list('waitlist',params.label,1,10) ] ).then( axios.spread(function(newlist,hotlist,waitlist ){ 
 return { newlist:newlist.data.data.rows, hotlist:hotlist.data.data.rows, waitlist:waitlist.data.data.rows, label:params.label //标簽ID,我們需要記錄下來 }
  })) 
},
data(){ 
return { 
type:'new', 
page_new: 1,//記錄最新問題清單的頁碼 page_hot: 1,//記錄熱門問題清單的頁碼 page_wait: 1//記錄等待回答清單的頁碼 } }
,methods:{ 
loadMore(){ 
if(this.type==='new'){ 
this.page_new++ problemApi.list('newlist',this.label,this.page_new,10).then( res=>{ this.newlist=this.newlist.concat( res.data.data.rows ) 
}) 
}if(this.type==='hot'){ this.page_hot++ problemApi.list('hotlist',this.label,this.page_hot,10).then( res=>{ this.hotlist=this.hotlist.concat( res.data.data.rows ) 
}) 
}
if(this.type==='wait'){ this.page_wait++ problemApi.list('waitlist',this.label,this.page_wait,10).then( res=>{ this.waitlist=this.waitlist.concat( res.data.data.rows ) 
}) 
} 
} 
} 
}
           

3.3 問答詳細頁

學員實作

3.4 釋出問題頁

學員實作。使用富文本編輯器(參見吐槽子產品的實作)

3.5 标簽清單與關注标簽

4 圖檔上傳

4.1 Data URL

Data URL給了我們一種很巧妙的将圖檔“嵌入”到HTML中的方法。跟傳統的用 img 标記将 伺服器上的圖檔引用到頁面中的方式不一樣,在Data URL協定中,圖檔被轉換成base64 編碼的字元串形式,并存儲在URL中,冠以mime-type。

傳統方式:

這種方式中, img 标記的 src 屬性指定了一個遠端伺服器上的資源。當網頁加載到浏覽 器中 時,浏覽器會針對每個外部資源都向伺服器發送一次拉取資源請求,占用網絡資 源。大多數的浏覽器都有一個并發請求數不能超過4個的限制。這意味着,如果一個 網頁 裡嵌入了過多的外部資源,這些請求會導緻整個頁面的加載延遲。而使用Data URL技 術,圖檔資料以base64字元串格式嵌入到了頁面中,與HTML成為一體,它的形式如下

vue-quill-editor的圖檔上傳預設采用Data URL方式。

4.2 輔助插件vue-quill-editor-upload

如果你不想使用Data URL方式存儲圖檔,我們可以通過一個輔助插件vue-quill-editor- upload 來讓vue-quill-editor實作傳統方式的上傳。 (1)安裝:

cnpm install vue‐quill‐editor‐upload ‐‐save
           

(2)修改submit.vue 引入插件

(3)将editorOption的值改為{}

data () { 
return { 
content: '', 
editorOption:{}//修改此處! 
} 
}
           

(4)新增created 鈎子函數

created () { 
this.editorOption = quillRedefine( { // 圖檔上傳的設定 
uploadConfig: { 
action:'http://localhost:3000/upload', // 必填參數 圖檔上傳地 址 
// 必選參數 res是一個函數,函數接收的response為上傳成功時伺服器返 回的資料
 // 你必須把傳回的資料中所包含的圖檔位址 return 回去 
 res: (respnse) => { 
 return respnse.info 
 },
 name: 'img' // 圖檔上傳參數名
  } 
  } 
  )
   }
           

4.3 Multer(了解)

課程中提供了上傳圖檔的服務端代碼 upload-server ,我們可以先測試運作後,對照在 線文檔閱讀并了解代碼(課程不要求學員獨立編寫此段代碼)

cnpm install 
npm run start
           

這段代碼主要應用兩項技術:

(1)Express --node.js的web架構 線上文檔: http://www.expressjs.com.cn/4x/api.html

(2)Multer --Express官方推出的,用于multipart/form-data請求資料處理的中間件 線上文檔: https://github.com/expressjs/multer/blob/master/doc/README-zh- cn.md

4.4 雲存儲解決方案-阿裡雲OSS

為了能夠解決海量資料存儲與彈性擴容,我們在十次方項目中采用雲存儲的解決方案- 阿 裡雲OSS。

4.4.1 準備工作

(1)申請阿裡雲賬号并完成實名認證: 可以使用我們之前發短信用的阿裡雲賬号。

(2)開通OSS: 登入阿裡雲官網。将滑鼠移至産品找到并單擊對象存儲OSS打開OSS産 品詳情頁面。在OSS産品詳情頁中的單擊立即開通。開通服務後,在OSS産品詳情頁面單 擊管理控制台直接進入OSS管理控制台界面。您也可以單擊位于官網首頁右上方菜單欄的 控制台,進入阿裡雲管理控制台首頁,然後單擊左側的對象存儲OSS菜單進入OSS管理控 制台界面。

第七天 黑馬十次方 吐槽清單與詳細頁、發吐槽與評論功能、問答頻道功能、掌握DataURL和阿裡雲OSS第7章 網站前台-吐槽與問答1 吐槽清單與詳細頁2 發吐槽與吐槽評論3 問答頻道4 圖檔上傳
第七天 黑馬十次方 吐槽清單與詳細頁、發吐槽與評論功能、問答頻道功能、掌握DataURL和阿裡雲OSS第7章 網站前台-吐槽與問答1 吐槽清單與詳細頁2 發吐槽與吐槽評論3 問答頻道4 圖檔上傳

(3)建立存儲空間

建立Bucket,命名為tensquare ,讀寫權限為公共讀

第七天 黑馬十次方 吐槽清單與詳細頁、發吐槽與評論功能、問答頻道功能、掌握DataURL和阿裡雲OSS第7章 網站前台-吐槽與問答1 吐槽清單與詳細頁2 發吐槽與吐槽評論3 問答頻道4 圖檔上傳

4.4.2 代碼編寫

(1)安裝ali-oss

cnpm install ali‐oss ‐‐save 
cnpm install co ‐‐save
           

(2)修改file-upload-demo-master的server.js

var co = require('co');
var OSS = require('ali‐oss'); 
var client = new OSS({ 
accessKeyId: 'LTAIWaEERTRWSD2', 
accessKeySecret: 'PznrHXxYvTcADAFFDDDJnoAokJ0NSWEWF', 
endpoint: 'oss‐cn‐beijing.aliyuncs.com', 
bucket: 'tensquare' 
});
           
app.post('/upload', upload.single('img'), (req, res) => 
{ 
// 沒有附帶檔案 
if (!req.file) { 
res.json({ ok: false }); 
return; 
} 
co(function* () { 
var stream = fs.createReadStream(req.file.path); 
var result = yield client.putStream(req.file.originalname, stream); console.log("result:"+result); 
res.json({ ok: true , info: result.url}) 
}).catch(function (err) { 
console.log(err); 
}); 
});
           

co :已同步的方式調用異步的代碼 配合yield關鍵字使用,将異步結果直接傳回。

繼續閱讀