前言
关于接口调用和页面的各种调优,都不必按部就班的按照这个样子来写。本来就是个小项目,作为一个前端菜鸟,我也在前进的路上,望知悉。
编辑器
用来写文章的编辑器,写博客,我们都是使用的markdown,由于对前端的不熟悉,只能胡乱选一个。最终使用的是tinymce,文档在这,这不是官方的。
⚠️!这是富文本编辑器,下面还有markdown编辑器, 两个都放出来了,可以按照个人喜好选择。
下载包
网址,从这里把Download TinyMCE Community
下载下来,然后再下载一个语言包,下载Chinese,不用说了把tinymcew下的langs删了,替换成下载好的语言包,在couponents下新建一个文件夹
editor
,把这个文件夹放进去。在editor下新建组件
index.vue
<template> <div> <Editor :init="init" v-model="content"></Editor> </div> </template> <script> import Editor from '@tinymce/tinymce-vue' import './tinymce.min.js' import './icons/default/icons.min.js' import './themes/silver/theme.min.js' import './langs/zh_CN' // 注册插件 import './plugins/preview/plugin.min.js' import './plugins/paste/plugin.min.js' import './plugins/wordcount/plugin.min.js' import './plugins/code/plugin.min.js' import './plugins/image/plugin.min.js' import './plugins/imagetools/plugin.min.js' import './plugins/media/plugin.min.js' import './plugins/codesample/plugin.min.js' import './plugins/lists/plugin.min.js' import './plugins/table/plugin.min.js' export default { components: {Editor}, props: { value: { type: String, default: '', }, }, data() { return { init: { language: 'zh_CN', height: '600px', plugins: 'preview paste wordcount code imagetools image media codesample lists table', branding: false, paste_data_images: true, toolbar: [ 'undo redo | styleselect |fontsizeselect| bold italic underline strikethrough |alignleft aligncenter alignright alignjustify |blockquote removeformat |numlist bullist table', 'preview paste code codesample |image media', ], //上传图片 images_upload_handler: async (blobInfo, succFun, failFun) => { let formdata = new FormData() formdata.append('file', blobInfo.blob(), blobInfo.name()) const { data: res } = await this.$http.post('api/admin/upload/', formdata) succFun('http://localhost:8081/'+res.data) failFun(this.$message.error('上传图片失败')) }, imagetools_cors_hosts: ['*'], imagetools_proxy: '', }, content: this.value, } }, watch: { value(newV) { this.content = newV }, content(newV) { this.$emit('input', newV) }, }, } </script> <style scoped> @import url('./skins/ui/oxide/skin.min.css'); @import url('./skins/content/default/content.min.css'); </style>
在写完了富文本之后,我发现我搞错了一点。博客当然是要用markdown啊😭,我本以为没有markdown编辑器的,哎,怪我认知不好。于是在一顿搜罗之后,我找到了一个巨好用的markdown编辑器。网址
npm install mavon-editor --save
直接安装,安装完成之后,直接全局引入。在main.js中。
import mavonEditor from "mavon-editor";
import "mavon-editor/dist/css/index.css";
Vue.use(mavonEditor);
然后直接使用,github上提供了他很多方法,这里我们直接引用。再根据需要,修改一下上传文件的方法。就大功告成。
<template>
<div>
<a-card>
<h3>{{id?'编辑文章':'新增文章'}}</h3>
<a-form-model :model="artInfo" ref="artInfoRef" :rules="artInfoRules" :hideRequiredMark="true">
<a-form-model-item label="文章标题" prop="title">
<a-input style="width:300px" v-model="artInfo.title"></a-input>
</a-form-model-item>
<a-form-model-item
style="width:200px"
prop="cid"
label="文章分类">
<a-select v-model="artInfo.cid" placeholder="请选择分类" @change="cateChange">
<a-select-option v-for="item in Catelist" :key="item.id" :value="item.id">{{item.name}}</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="文章描述" prop="desc">
<a-input type="textarea" v-model="artInfo.desc"></a-input>
</a-form-model-item>
<a-form-model-item label="缩略图" prop="img">
<a-upload
name="file"
:multiple="false"
:action="uploadUrl"
:headers="headers"
@change="upChange"
listType="picture"
>
<a-button> <a-icon type="upload" /> 上传图片 </a-button>
<br/>
<template v-if="id">
<img :src="artInfo.img" style="width:120px;height:100px">
</template>
</a-upload>
</a-form-model-item>
<a-form-model-item label="内容" prop="content">
<!-- <Editor v-model="artInfo.content"></Editor> -->
<mavon-editor
ref="md"
placeholder="请输入文档内容..."
:boxShadow="false"
style="z-index:1;border: 1px solid #d9d9d9;height:50vh"
v-model="artInfo.content"
:toolbars="toolbars"
@imgAdd="$imgAdd"
/>
</a-form-model-item>
<a-form-model-item>
<a-button type="primary"
style="margin-right:15px"
@click="artOk(artInfo.id)"
>
{{artInfo.id?"更新":'提交'}}
</a-button>
<a-button type="danger" @click="addCancel">取消</a-button>
</a-form-model-item>
</a-form-model>
</a-card>
</div>
</template>
<script>
import {Url} from "../../plugins/http"
import Editor from "../editor/index"
export default {
components:{Editor},
props:['id'],
data(){
return{
artInfo:{
id:0,
title:'',
cid:undefined,
desc:'',
content:'',
img:''
},
Catelist:[],
uploadUrl:Url+'/api/admin/upload/',
headers:{},
artInfoRules: {
title: [{ required: true, message: '请输入文章标题', trigger: 'change' }],
cid: [{ required: true, message: '请选择文章分类', trigger: 'change' }],
desc: [
{ required: true, message: '请输入文章描述', trigger: 'change' },
{ max: 120, message: '描述最多可写120个字符', trigger: 'change' },
],
content: [{ required: true, message: '请输入文章内容', trigger: 'change' }],
},
// markdown对象
toolbars: {
bold: true, // 粗体
italic: true, // 斜体
header: true, // 标题
underline: true, // 下划线
strikethrough: true, // 中划线
mark: true, // 标记
superscript: true, // 上角标
subscript: true, // 下角标
quote: true, // 引用
ol: true, // 有序列表
ul: true, // 无序列表
link: true, // 链接
imagelink: true, // 图片链接
code: true, // code
table: true, // 表格
fullscreen: true, // 全屏编辑
readmodel: true, // 沉浸式阅读
htmlcode: true, // 展示html源码
help: true, // 帮助
/* 1.3.5 */
undo: true, // 上一步
redo: true, // 下一步
trash: true, // 清空
save: false, // 保存(触发events中的save事件)
/* 1.4.2 */
navigation: true, // 导航目录
/* 2.1.8 */
alignleft: true, // 左对齐
aligncenter: true, // 居中
alignright: true, // 右对齐
/* 2.2.1 */
subfield: true, // 单双栏模式
preview: true // 预览
}
}
},
created(){
this.getCateList()
this.headers = {Authorization:`Bearer ${window.sessionStorage.getItem('token')}`}
if(this.id){
this.getArtInfo(this.id)
}
},
methods:{
// 查询文章信息
async getArtInfo(id){
const {data: res} = await this.$http.get(`api/v1/article/${id}/`)
if(res.code != 200) return this.$$message.error(res.msg)
this.artInfo = res.data
this.artInfo.id = res.data.ID
},
// 获取分类
async getCateList() {
const { data: res } = await this.$http.get('api/v1/category/',{params: {
size: 100,
page: 1,
},})
if (res.code !== 200) return this.$message.error(res.msg)
this.Catelist = res.data
},
cateChange(val){
this.artInfo.cid = val
},
upChange(info){
if (info.file.status !== 'uploading') {
}
if (info.file.status === 'done') {
this.$message.success('上传成功');
const imgUrl = info.file.response.data
this.artInfo.img = imgUrl
} else if (info.file.status === 'error') {
this.$message.error(`上传失败`);
}
},
// 提交
artOk(id){
this.$refs.artInfoRef.validate(async (valid) => {
if (!valid) return this.$message.error('参数验证未通过,请按要求录入文章内容')
if (id === 0) {
const { data: res } = await this.$http.post('/api/admin/article/', this.artInfo)
if (res.code !== 200) return this.$message.error(res.msg)
this.$router.push('/admin/artlist')
this.$message.success('添加文章成功')
} else {
const { data: res } = await this.$http.put(`/api/admin/article/${id}/`, this.artInfo)
if (res.code !== 200) return this.$message.error(res.msg)
this.$router.push('/admin/artlist')
this.$message.success('更新文章成功')
}
})
},
// 取消
addCancel(){
this.$refs.artInfoRef.resetFields()
},
// 上传图片方法
async $imgAdd(pos, $file) {
var formdata = new FormData();
formdata.append('file', $file);
const {data: res} = await this.$http.post("/api/admin/upload/",formdata,{ 'Content-Type': 'multipart/form-data' })
this.$refs.md.$imglst2Url([[pos, "http://localhost:8081/"+res.data]])
},
}
}
</script>
<style>
</style>
这样的话,我们以后修改起来也是很方便的,只是,在后台我们需要一个渲染库。
渲染库
渲染库使用的是这个
安装
go get -u github.com/gomarkdown/markdown
可以在utils下新建一个Markdown.go
,写成工具函数。
package utils
import (
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
)
// 渲染html
func Render(data string) string {
htmlFlags := html.CommonFlags | html.HrefTargetBlank
opts := html.RendererOptions{Flags: htmlFlags}
renderer := html.NewRenderer(opts)
md := []byte(data)
content := markdown.ToHTML(md, nil, renderer)
return string(content)
}
然后只需要在必要的地方来使用这个工具即可。
- Post link: https://www.godhearing.cn/gin-vue-da-jian-ge-ren-bo-ke-9/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.