前端学习(2457):文章发布
生活随笔
收集整理的這篇文章主要介紹了
前端学习(2457):文章发布
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
# 五、文章發(fā)布## 創(chuàng)建組件并配置路由1、創(chuàng)建 `src/views/publish/index.vue` 組件```html
<template><div class="publish-container">發(fā)布文章</div>
</template><script>
export default {name: 'PublishIndex',components: {},props: {},data () {return {}},computed: {},watch: {},created () {},mounted () {},methods: {}
}
</script><style scoped lang="less"></style>```2、配置頁面路由<img src="assets/image-20200425162406736.png" alt="image-20200425162406736" style="zoom:50%;" />3、訪問測試## 頁面布局```html
<template><div class="publish-container"><el-card class="box-card"><div slot="header" class="clearfix"><!-- 面包屑路徑導(dǎo)航 --><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item to="/">首頁</el-breadcrumb-item><el-breadcrumb-item>發(fā)布文章</el-breadcrumb-item></el-breadcrumb><!-- /面包屑路徑導(dǎo)航 --></div><el-form ref="form" :model="form" label-width="40px"><el-form-item label="標(biāo)題"><el-input v-model="form.name"></el-input></el-form-item><el-form-item label="內(nèi)容"><el-input type="textarea" v-model="form.desc"></el-input></el-form-item><el-form-item label="封面"><el-radio-group v-model="form.resource"><el-radio label="單圖"></el-radio><el-radio label="三圖"></el-radio><el-radio label="無圖"></el-radio><el-radio label="自動"></el-radio></el-radio-group></el-form-item><el-form-item label="頻道"><el-select v-model="form.region" placeholder="請選擇頻道"><el-option label="區(qū)域一" value="shanghai"></el-option><el-option label="區(qū)域二" value="beijing"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">發(fā)表</el-button><el-button>存入草稿</el-button></el-form-item></el-form></el-card></div>
</template><script>
export default {name: 'PublishIndex',components: {},props: {},data () {return {form: {name: '',region: '',date1: '',date2: '',delivery: false,type: [],resource: '',desc: ''}}},computed: {},watch: {},created () {},mounted () {},methods: {onSubmit () {console.log('submit!')}}
}
</script><style scoped lang="less"></style>```## 處理表單數(shù)據(jù)綁定> 思路:根據(jù)后端接口的要求處理綁定數(shù)據(jù)綁定```html
<template><div class="publish-container"><el-card class="box-card"><div slot="header" class="clearfix"><!-- 面包屑路徑導(dǎo)航 --><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item to="/">首頁</el-breadcrumb-item><el-breadcrumb-item>發(fā)布文章</el-breadcrumb-item></el-breadcrumb><!-- /面包屑路徑導(dǎo)航 --></div><el-form ref="form" :model="form" label-width="40px"><el-form-item label="標(biāo)題"><el-input v-model="article.title"></el-input></el-form-item><el-form-item label="內(nèi)容"><el-input type="textarea" v-model="article.content"></el-input></el-form-item><el-form-item label="封面"><el-radio-group v-model="article.cover.type"><el-radio :label="1">單圖</el-radio><el-radio :label="3">三圖</el-radio><el-radio :label="0">無圖</el-radio><el-radio :label="-1">自動</el-radio></el-radio-group></el-form-item><el-form-item label="頻道"><el-select v-model="form.region" placeholder="請選擇頻道"><el-option label="區(qū)域一" value="shanghai"></el-option><el-option label="區(qū)域二" value="beijing"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">發(fā)表</el-button><el-button>存入草稿</el-button></el-form-item></el-form></el-card></div>
</template><script>
export default {name: 'PublishIndex',components: {},props: {},data () {return {form: {name: '',region: '',date1: '',date2: '',delivery: false,type: [],resource: '',desc: ''},article: {title: '', // 文章標(biāo)題content: '', // 文章內(nèi)容cover: { // 文章封面type: 0, // 封面類型 -1:自動,0-無圖,1-1張,3-3張images: [] // 封面圖片的地址}}}},computed: {},watch: {},created () {},mounted () {},methods: {onSubmit () {console.log('submit!')}}
}
</script><style scoped lang="less"></style>```## 處理文章頻道數(shù)據(jù)一、展示頻道列表1、請求獲取頻道列表數(shù)據(jù)<img src="assets/image-20200425163038862.png" alt="image-20200425163038862" style="zoom:50%;" />2、綁定到模板中展示<img src="assets/image-20200425163137597.png" alt="image-20200425163137597" style="zoom:50%;" />二、將頻道綁定到表單元素選擇器1、在 article 中添加頻道數(shù)據(jù)字段<img src="assets/image-20200425163209293.png" alt="image-20200425163209293" style="zoom:50%;" />2、將數(shù)據(jù)綁定到頻道選擇器中<img src="assets/image-20200425163242141.png" alt="image-20200425163242141" style="zoom:50%;" />## 發(fā)布文章一、封裝數(shù)據(jù)接口```js
/*** 新建文章*/
export const addArticle = (data, draft = false) => {return request({method: 'POST',url: '/mp/v1_0/articles',params: {draft // 是否存為草稿(true 為草稿)},data})
}
```二、在發(fā)布文章組件中請求調(diào)用1、加載請求方法<img src="assets/image-20200425163618795.png" alt="image-20200425163618795" style="zoom:50%;" />2、給發(fā)布和存入草稿綁定事件處理函數(shù)<img src="assets/image-20200425163526654.png" alt="image-20200425163526654" style="zoom:50%;" />3、處理函數(shù)如下```js
onPublish (draft = false) {// 找到數(shù)據(jù)接口// 封裝請求方法// 請求提交表單addArticle(this.article, draft).then(res => {// 處理響應(yīng)結(jié)果// console.log(res)this.$message({message: '發(fā)布成功',type: 'success'})})
}
```## 編輯文章### 展示編輯文章內(nèi)容1、封裝獲取文章的數(shù)據(jù)接口```js
/*** 獲取指定文章*/
export const getArticle = articleId => {return request({method: 'GET',url: `/mp/v1_0/articles/${articleId}`})
}
```2、點擊編輯,導(dǎo)航到發(fā)布文章頁面<img src="assets/image-20200425163826162.png" alt="image-20200425163826162" style="zoom:50%;" />3、在發(fā)布文章頁面組件中,處理加載編輯文章內(nèi)容<img src="assets/image-20200425164127166.png" alt="image-20200425164127166" style="zoom:50%;" /><img src="assets/image-20200425164215467.png" alt="image-20200425164215467" style="zoom:50%;" />### 提交更新1、封裝更新文章的數(shù)據(jù)接口```js
/*** 編輯文章*/
export const updateArticle = (articleId, data, draft = false) => {return request({method: 'PUT',url: `/mp/v1_0/articles/${articleId}`,params: {draft // 是否存為草稿(true 為草稿)},data})
}
```2、加載請求方法<img src="assets/image-20200425164349629.png" alt="image-20200425164349629" style="zoom:50%;" />3、修改發(fā)布文章的處理邏輯```js
onPublish (draft = false) {// 找到數(shù)據(jù)接口// 封裝請求方法// 請求提交表單// 如果是修改文章,則執(zhí)行修改操作,否則執(zhí)行添加操作const articleId = this.$route.query.idif (articleId) {// 執(zhí)行修改操作updateArticle(articleId, this.article, draft).then(res => {console.log(res)this.$message({message: `${draft ? '存入草稿' : '發(fā)布'}成功`,type: 'success'})// 跳轉(zhuǎn)到內(nèi)容管理頁面this.$router.push('/article')})} else {addArticle(this.article, draft).then(res => {// 處理響應(yīng)結(jié)果// console.log(res)this.$message({message: `${draft ? '存入草稿' : '發(fā)布'}成功`,type: 'success'})// 跳轉(zhuǎn)到內(nèi)容管理頁面this.$router.push('/article')})}
},
```## 使用富文本編輯器基于 Vue 的富文本編輯器有很多,例如官方就收錄推薦了一些: https://github.com/vuejs/awesome-vue#rich-text-editing 。這里我們以 element-tiptap 為例。- GitHub 倉庫:https://github.com/Leecason/element-tiptap
- 在線示例:https://leecason.github.io/element-tiptap
- 中文文檔:https://github.com/Leecason/element-tiptap/blob/master/README_ZH.md1、安裝```shell
npm i element-tiptap
```2、初始配置```html
<template><el-tiptap v-model="content" :extensions="extensions"></el-tiptap>
</template><script>import {ElementTiptap,Doc,Text,Paragraph,Heading,Bold,Underline,Italic,Image,Strike,ListItem,BulletList,OrderedList,TodoItem,TodoList,HorizontalRule,Fullscreen,Preview,CodeBlock
} from 'element-tiptap'
import 'element-tiptap/lib/index.css'export default {components: {'el-tiptap': ElementTiptap},data () {return {content: 'hello world',extensions: [new Doc(),new Text(),new Paragraph(),new Heading({ level: 3 }),new Bold({ bubble: true }), // 在氣泡菜單中渲染菜單按鈕new Image(),new Underline(), // 下劃線new Italic(), // 斜體new Strike(), // 刪除線new HorizontalRule(), // 華麗的分割線new ListItem(),new BulletList(), // 無序列表new OrderedList(), // 有序列表new TodoItem(),new TodoList(),new Fullscreen(),new Preview(),new CodeBlock()]}}
}
</script>```## 處理富文本編輯器中的圖片<img src="assets/image-20200426121121725.png" alt="image-20200426121121725" style="zoom:50%;" />1、創(chuàng)建 `src/api/image.js` 封裝數(shù)據(jù)接口```js
/*** 素材請求相關(guān)模塊*/import request from '@/utils/request'/*** 上傳圖片素材*/
export const uploadImage = data => {return request({method: 'POST',url: '/mp/v1_0/user/images',// 一般文件上傳的接口都要求把請求頭中的 Content-Type 設(shè)置為 multipart/form-data,但是我們使用 axios 上傳文件的話不需要手動設(shè)置,你只要給 data 一個 FormData 對象即可。// new FormData()data})
}```2、自定義圖片上傳到服務(wù)器<img src="assets/image-20200426173740077.png" alt="image-20200426173740077" style="zoom:50%;" />## 表單驗證處理<img src="assets/image-20200426173930626.png" alt="image-20200426173930626" style="zoom:50%;" />驗證規(guī)則配置對象:```js
formRules: {title: [{ required: true, message: '請輸入文章標(biāo)題', trigger: 'blur' },{ min: 5, max: 30, message: '長度在 5 到 30 個字符', trigger: 'blur' }],content: [// { required: true, message: '請輸入文章內(nèi)容', trigger: 'change' }{validator (rule, value, callback) {console.log('content validator')if (value === '<p></p>') {// 驗證失敗callback(new Error('請輸入文章內(nèi)容'))} else {// 驗證通過callback()}}},{ required: true, message: '請輸入文章內(nèi)容', trigger: 'blur' }],channel_id: [{ required: true, message: '請選擇文章頻道' }]
}
```## 文章封面> 該業(yè)務(wù)功能比較復(fù)雜,需要自定義封裝組件,所以放到項目最后講解。1、創(chuàng)建 `src/views/publish/components/upload-image.vue` 組件并寫入```html
<template><div>上傳圖片組件</div>
</template><script>export default {name: "UploadImage",components: {},props: {},data() {return {};},computed: {},watch: {},created() {},methods: {}};
</script><style scoped></style>
```2、在文章發(fā)布中加載使用> 注冊> 在模板中使用### 使用對話框```html
<template><div class="upload-image"><div class="preview" @click="centerDialogVisible=true"><!-- <img src="" class="avatar"> --><i class="el-icon-plus avatar-uploader-icon"></i></div><!--visible 控制對話框的顯示和隱藏--><el-dialogtitle="請選擇文章封面圖片":visible.sync="centerDialogVisible"width="30%"center><span slot="footer" class="dialog-footer"><el-button @click="centerDialogVisible = false">取 消</el-button><el-button type="primary" @click="centerDialogVisible = false">確 定</el-button></span></el-dialog></div>
</template><script>export default {name: "UploadImage",components: {},props: {},data() {return {centerDialogVisible: false};},computed: {},watch: {},created() {},methods: {}};
</script><style scoped>.upload-image {border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;}.upload-image .el-upload:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 178px;height: 178px;line-height: 178px;text-align: center;}.avatar {width: 178px;height: 178px;display: block;}
</style>
```### 展示素材庫```html
<template><div class="upload-image"><div class="preview" @click="onUploadShow"><!-- <img src="" class="avatar"> --><i class="el-icon-plus avatar-uploader-icon"></i></div><!--visible 控制對話框的顯示和隱藏--><el-dialogtitle="請選擇文章封面圖片":visible.sync="centerDialogVisible"width="50%"center><!-- 標(biāo)簽導(dǎo)航 --><!--el-tabs 組件v-model 雙向綁定數(shù)據(jù)驅(qū)動視圖:當(dāng)綁定數(shù)據(jù)發(fā)生改變,激活的標(biāo)簽頁受影響視圖影響數(shù)據(jù):當(dāng)標(biāo)簽改變的時候,標(biāo)簽的 name 會同步到數(shù)據(jù)中l(wèi)abel 標(biāo)簽的標(biāo)題name 相當(dāng)于標(biāo)簽的 id--><el-tabs v-model="activeName"><el-tab-pane label="素材庫" name="first"><!-- 標(biāo)簽內(nèi)容寫到里面來 --><!--radio 有個 change 事件當(dāng)選擇的 radio 改變的時候會觸發(fā)--><el-radio-group v-model="activeImage" @change="loadImages"><el-radio label="all">全部</el-radio><el-radio label="collect">收藏</el-radio></el-radio-group><el-row :gutter="20"><el-col :span="6" v-for="item in images" :key="item.id"><img height="100" :src="item.url" /></el-col></el-row></el-tab-pane><el-tab-pane label="上傳圖片" name="second">配置管理</el-tab-pane></el-tabs><!-- /標(biāo)簽導(dǎo)航 --><span slot="footer" class="dialog-footer"><el-button @click="centerDialogVisible = false">取 消</el-button><el-button type="primary" @click="centerDialogVisible = false">確 定</el-button></span></el-dialog></div>
</template><script>export default {name: "UploadImage",components: {},props: {},data() {return {centerDialogVisible: false, // 對話框的顯示狀態(tài)activeName: "first", // 激活的標(biāo)簽頁activeImage: "all", // 激活的圖片篩選類型images: []};},computed: {},watch: {},created() {console.log(123);},methods: {onUploadShow() {// 請求加載數(shù)據(jù)this.loadImages();// 顯示彈窗this.centerDialogVisible = true;},loadImages() {this.$axios({method: "GET",url: "/user/images",params: {// this.activeImage 雙向綁定了 radio 選擇框組// 所以獲取 this.activeImage 也就是在獲取選中的那個 radio 的狀態(tài)collect: this.activeImage === "collect" // 是否獲取收藏圖片}}).then(res => {this.images = res.data.data.results;}).catch(err => {console.log(err);});}}};
</script><style scoped>.upload-image {border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;}.upload-image .el-upload:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 178px;height: 178px;line-height: 178px;text-align: center;}.avatar {width: 178px;height: 178px;display: block;}
</style>
```### 處理選擇圖片1、添加一個數(shù)據(jù)字段用來存儲當(dāng)前點擊的圖片項的索引2、模板綁定### 數(shù)據(jù)綁定1、在父組件中綁定數(shù)組元素給圖片上傳組件2、在上傳圖片組件中> 聲明 value 接收數(shù)據(jù)> 點擊對話框確認(rèn)觸發(fā):將所選的圖片路徑發(fā)送給父組件### 上傳圖片1、添加上傳圖片組件2、記錄選擇的上傳圖片3、對話框確定的時候## 禁用路由緩存我們發(fā)現(xiàn)一個小問題,從編輯文章導(dǎo)航到發(fā)布文章,表單內(nèi)容并沒有被清空,這是因為兩個路由共用的同一個組件,兩者之間相互跳轉(zhuǎn)的時候,原來的組件實例會被復(fù)用。 因為兩個路由都渲染同個組件,比起銷毀再創(chuàng)建,復(fù)用則顯得更加高效。**不過,這也意味著組件的生命周期鉤子不會再被調(diào)用**。路由默認(rèn)提供的這個功能的用意是好的,但是有時候卻會帶來問題,解決方案就是:**禁用緩存**。在路由出口 `router-view` 上添加一個唯一的 `key` 即可。> 詳細(xì)內(nèi)容請查閱官方文檔:[響應(yīng)路由參數(shù)的變化](<[https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html#%E5%93%8D%E5%BA%94%E8%B7%AF%E7%94%B1%E5%8F%82%E6%95%B0%E7%9A%84%E5%8F%98%E5%8C%96](https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html#響應(yīng)路由參數(shù)的變化)>)。
?
總結(jié)
以上是生活随笔為你收集整理的前端学习(2457):文章发布的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “约见”面试官系列之常见面试题第十一篇之
- 下一篇: 前端学习(2421):项目反馈