Edit.vue
<template>
<div id="edit">
<ClassicHeader>
<template v-slot:left>
<span>編輯隨筆</span>
</template>
<template v-slot:right>
<el-button @click="newPost('Management')">存爲草稿</el-button>
<el-button @click="newPost()">存爲草稿並繼續編輯</el-button>
</template>
</ClassicHeader>
<main>
<div id="post_title">
<el-input v-model="post_title" placeholder="標題"></el-input>
</div>
<div id="post_content">
<editor :init="tinymce_init" v-model="post_content" />
</div>
<div id="post_category">
<SubTitle>分類</SubTitle>
<el-checkbox-group v-model="checkList">
<el-checkbox v-for="category in categories" :key="category.id" :label="category.id">{{category.name}}</el-checkbox>
</el-checkbox-group>
</div>
</main>
</div>
</template>
<script>
import axios from 'axios'
import qs from 'qs'
import Editor from '@tinymce/tinymce-vue'
import ClassicHeader from '@/components/ClassicHeader.vue'
import SubTitle from '@/components/SubTitle'
export default {
name: 'Edit',
components: {
'editor': Editor,
ClassicHeader,
SubTitle,
},
data() {
return {
post_title: '',
post_content: '',
checkList: [],
tinymce_init: {
height: 654,
language: 'zh-Hans',
menubar: false,
plugins: 'wordcount table searchreplace save preview media lists link insertdatetime image emoticons codesample code charmap autolink anchor advlist',
toolbar: ['bold italic underline strikethrough | numlist bullist | forecolor backcolor | alignleft aligncenter alignright alignjustify | outdent indent | searchreplace | preview wordcount | print',
'link unlink anchor | removeformat | codesample | code | blocks fontfamily | image media insertdatetime insertfile emoticons charmap | undo redo',
'table tabledelete | tableprops tablerowprops tablecellprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol'],
},
categories: [],
}
},
mounted() {
this.reloadCategories()
},
methods: {
reloadCategories() {
axios.get(this.$url_categories)
.then(resp => {
this.categories = resp.data
})
.catch(err => {
console.log(err)
})
},
newPost(jump2 = 'Edit2') {
if (!this.post_title && this.post_title.trim() === '') {
this.$message.error('標題不能爲空!');
return
}
console.log(this.checkList)
const DATA = qs.stringify({
'title': this.post_title,
'content': this.post_content,
'category': JSON.stringify(this.checkList),
});
const CONFIG = {
method: 'post',
url: this.$url_posts,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data : DATA
};
// 把屏幕鎖了防止亂點
const LOADING = this.$loading({
lock: true,
// spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
axios(CONFIG)
.then((resp) => {
let post = resp.data
setTimeout(() => {
// 至少鎖1秒才解除
LOADING.close();
this.$message({
type: 'success',
message: '操作成功',
});
if (this.$route.name !== jump2) {
this.$router.push({
name: jump2,
query: {
post_id: post.id,
},
});
}
}, 1000);
})
.catch(function (error) {
console.log(error);
});
}
},
}
</script>
<style scoped>
#edit {
display: flex;
flex-direction: column;
}
main {
display: flex;
flex-direction: column;
padding-bottom: 30px;
}
#post_title {
padding: 10px 10px;
border: 1px solid #dcdfe6;
}
#post_content {
padding: 10px 10px;
border: 1px solid #dcdfe6;
}
#post_category {
padding: 10px 10px;
border: 1px solid #dcdfe6;
}
</style>
這段代碼也是一個Vue.js組件,實現了一個新建文章的編輯頁面。頁面包含一個標題、一個內容編輯器和一個分類複選框,以及兩個按鈕:存爲草稿、存爲草稿並繼續編輯。
與前一個組件不同的是,該組件的post屬性被拆分成了post_title和post_content兩個變量,用於分別存儲文章的標題和內容。另外,該組件中沒有定義post的狀態屬性。相應地,該組件的方法中也沒有定義發佈文章的方法,只有一個newPost()方法,用於將用戶編輯的文章保存爲草稿。
該組件的實現與前一個組件的大部分代碼類似,只是去除了一些發佈文章相關的邏輯,而增加了一些保存草稿相關的邏輯。在newPost()方法中,用戶編輯的文章數據被包裝成一個表單數據,通過axios發送到服務器進行保存。保存成功後,根據不同的參數值,分別跳轉到編輯頁面或文章管理頁面。
最後,該組件也定義了一些樣式,用於控制頁面的佈局和樣式,其中#edit用於設置頁面的顯示方式爲flex佈局,#post_title、#post_content和#post_category用於設置標題、內容編輯器和分類複選框的邊框和內邊距。這些樣式是通過Vue.js的scoped樣式功能實現的,只對當前組件的DOM元素生效,不影響全局樣式。
Edit2.vue
<template>
<div id="edit2">
<ClassicHeader>
<template v-slot:left>
<span>正在編輯隨筆:{{ post_id }}</span>
</template>
<template v-slot:right>
<el-button @click="publish" :disabled="post.state === '已發佈'">發佈</el-button>
<el-button @click="updatePost()">保存</el-button>
<el-button @click="updateAndExit()">保存並退出編輯模式</el-button>
</template>
</ClassicHeader>
<main>
<div id="post_title">
<el-input v-model="post.title" placeholder="標題"></el-input>
</div>
<div id="post_content">
<editor :init="tinymce_init" v-model="post.content" />
</div>
<div id="post_category">
<SubTitle>分類</SubTitle>
<el-checkbox-group v-model="checkList">
<el-checkbox v-for="category in categories" :key="category.id" :label="category.id">{{category.name}}</el-checkbox>
</el-checkbox-group>
</div>
</main>
</div>
</template>
<script>
import axios from 'axios'
import qs from 'qs'
import Editor from '@tinymce/tinymce-vue'
import ClassicHeader from '@/components/ClassicHeader.vue'
import SubTitle from '@/components/SubTitle'
export default {
name: 'Edit2',
components: {
'editor': Editor,
ClassicHeader,
SubTitle,
},
data() {
return {
post: {
title: '',
content: '',
state: '',
},
categories: [],
checkList: [],
tinymce_init: {
height: 654,
language: 'zh-Hans',
menubar: false,
plugins: 'wordcount table searchreplace save preview media lists link insertdatetime image emoticons codesample code charmap autolink anchor advlist',
toolbar: ['bold italic underline strikethrough | numlist bullist | forecolor backcolor | alignleft aligncenter alignright alignjustify | outdent indent | searchreplace | preview wordcount | print',
'link unlink anchor | removeformat | codesample | code | blocks fontfamily | image media insertdatetime insertfile emoticons charmap | undo redo',
'table tabledelete | tableprops tablerowprops tablecellprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol'],
},
}
},
computed: {
post_id: {
get() {
return this.$route.query.post_id
},
}
},
mounted() {
this.reloadCategories()
this.reloadPost()
},
methods: {
reloadPost() {
axios.get(this.$url_posts + `/${ this.post_id }`)
.then(resp => {
this.post = resp.data
// 不懂爲啥,對於數組不管是發送還是接收都要手動進行 解析/轉化
this.checkList = JSON.parse(this.post.category)
})
.catch(err => {
console.log(err)
})
},
reloadCategories() {
axios.get(this.$url_categories)
.then(resp => {
this.categories = resp.data
})
.catch(err => {
console.log(err)
})
},
publish() {
this.post.state = '已發佈'
this.post.pubDate = new Date()
this.updateAndExit()
},
updateAndExit() {
this.updatePost(true)
},
updatePost(jump2 = false) {
if (!this.post.title && this.post.title.trim() === '') {
this.$message.error('標題不能爲空!');
return
}
const data = qs.stringify({
'title': this.post.title,
'content': this.post.content,
'state': this.post.state,
'pubDate': this.post.pubDate,
'category': JSON.stringify(this.checkList),
});
const config = {
method: 'post',
url: this.$url_posts + `/${this.post_id}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data : data
};
const LOADING = this.$loading({
lock: true,
background: 'rgba(0, 0, 0, 0.7)'
});
axios(config)
.then((resp) => {
let post = resp.data
console.log(post)
setTimeout(() => {
LOADING.close();
this.$message({
type: 'success',
message: '操作成功',
});
if (jump2) {
if (this.$route.name !== 'Management') {
this.$router.push({
name: 'Management',
});
}
}
}, 1000);
})
.catch(function (error) {
console.log(error);
});
},
},
}
</script>
<style scoped>
#edit2 {
display: flex;
flex-direction: column;
padding-bottom: 30px;
}
#post_title {
padding: 10px 10px;
border: 1px solid #dcdfe6;
}
#post_content {
padding: 10px 10px;
border: 1px solid #dcdfe6;
}
#post_category {
padding: 10px 10px;
border: 1px solid #dcdfe6;
}
</style>
這段代碼是一個Vue.js組件,主要實現了一個編輯頁面的功能。頁面包含一個標題、一個內容編輯器、一個分類複選框和三個按鈕:發佈、保存、保存並退出編輯模式。
該組件首先引入了一些第三方庫和組件,如axios(一個基於Promise的HTTP庫)、qs(一個處理URL參數和請求payload的庫)、@tinymce/tinymce-vue(一個Vue.js組件,提供了一個所見即所得的富文本編輯器)以及一些自定義組件。接着定義了一些組件內部的data和computed屬性,用於存儲頁面的狀態和一些計算屬性。其中post屬性用於存儲用戶編輯的文章的標題、內容和狀態,categories屬性用於存儲文章分類列表,checkList屬性用於存儲用戶選擇的分類,tinymce_init屬性用於配置富文本編輯器的一些參數,post_id屬性用於獲取路由參數中的post_id參數。
該組件定義了一些方法,用於加載文章和分類、發佈文章、保存文章和退出編輯模式。其中reloadPost()和reloadCategories()方法用於加載文章和分類列表,publish()方法用於將文章狀態設置爲已發佈,並調用updateAndExit()方法保存並退出編輯模式,updateAndExit()方法用於保存文章並退出編輯模式,updatePost()方法用於保存文章的具體實現。該方法首先對文章標題進行非空校驗,然後將用戶編輯的文章數據包裝成一個表單數據,通過axios發送到服務器進行保存,並在保存成功後顯示一個操作成功的提示消息。
最後,該組件還定義了一些樣式,用於控制頁面的佈局和樣式。其中#edit2用於設置頁面的顯示方式爲flex佈局,#post_title、#post_content和#post_category用於設置標題、內容編輯器和分類複選框的邊框和內邊距。這些樣式是通過Vue.js的scoped樣式功能實現的,只對當前組件的DOM元素生效,不影響全局樣式。