第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">×</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">×</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管理控 制台界面。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLzMGVPpXSE10MFpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLxczN1IzM0IjMwMzNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
(3)建立存儲空間
建立Bucket,命名為tensquare ,讀寫權限為公共讀
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關鍵字使用,将異步結果直接傳回。