27.blog前端-发布文章

article/2025/10/28 7:23:43

点击写文章,会跳转到该页面

点击右上角的发布,会弹出发布的对话框因此,我们要调用文章分类列表和文章标签列表的接口

以及如果是点击文字的编辑按钮进入该页面的话,还需要通过调用文章id获取文章详情的接口

还需要调用发布文章的接口

/*** 获取分类列表*/
export function getAllCategorys()
{return request({url:"/categorys",method:'GET',})
}
/*** 查询标签列表*/
export function getAllTags()
{return request({url:"/tags",method:"GET",})
}
/*** 通过文章id获取文章详情* @param PageParams*/
export function getArticleById(id) 
{return request({url: `/articles/${id}`,method: 'POST'})
}
/*** 通过token和文章参数发布文章* @param PageParams*/
export function publishArticle(article,token)
{return request({headers: {'Authorization': token},url: '/articles/publish',method: 'post',data: article})
}

这里的header是复用了baseHeader组件。

将simple传入到baseHeader中,baseHeader通过props获取,将之前首页展示的首页、文章分类、标签、文章归档全部屏蔽掉

然后用了slot,将传入的写文章、发布、取消全部插入到baseHeader中

<template><div id="write" v-title :data-title="title"><el-container><!--标题、发布、取消按钮--><base-header :simple=true><el-col :span="4" :offset="2"><div class="me-write-info">写文章</div></el-col><el-col :span="4" :offset="6"><div class="me-write-btn"><el-button round @click="publishShow">发布</el-button><el-button round @click="cancel">取消</el-button></div></el-col></base-header><el-container class="me-area me-write-box"><el-main class="me-write-main"><div class="me-write-title"><el-input resize="none"type="textarea"autosizev-model="articleForm.title"placeholder="请输入标题"class="me-write-input"></el-input></div><div id="placeholder" style="visibility: hidden;height: 89px;display: none;"></div><markdown-editor :editor="articleForm.editor" class="me-write-editor"></markdown-editor></el-main></el-container><!--点击发布之后弹出的对话框--><el-dialog title="摘要 分类 标签":visible.sync="publishVisible":close-on-click-modal=falsecustom-class="me-dialog"><el-form :model="articleForm" ref="articleForm" :rules="rules"><el-form-item prop="summary"><el-input type="textarea"v-model="articleForm.summary":rows="6"placeholder="请输入摘要"></el-input></el-form-item><el-form-item label="文章分类" prop="category"><el-select v-model="articleForm.category" value-key="id" placeholder="请选择文章分类"><el-option v-for="c in categorys" :key="c.id" :label="c.categoryName" :value="c"></el-option></el-select></el-form-item><el-form-item label="文章标签" prop="tags"><el-checkbox-group v-model="articleForm.tags"><el-checkbox v-for="t in tags" :key="t.id" :label="t.id" name="tags">{{t.tagName}}</el-checkbox></el-checkbox-group></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="publishVisible = false">取 消</el-button><el-button type="primary" @click="publish('articleForm')">发布</el-button></div></el-dialog></el-container></div>
</template><script>import BaseHeader from '@/views/BaseHeader'import MarkdownEditor from '@/components/markdown/MarkdownEditor'import {publishArticle, getArticleById} from '@/api/article'import {getAllCategorys} from '@/api/category'import {getAllTags} from '@/api/tag'export default{name: 'publishArticle',mounted(){if(this.$route.params.id){this.getArticleById(this.$route.params.id)}/*获取是所有标签和分类*/this.getCategorysAndTags();this.editorToolBarToFixedWrapper = this.$_.throttle(this.editorToolBarToFixed, 200)window.addEventListener('scroll', this.editorToolBarToFixedWrapper, false);},beforeDestroy(){window.removeEventListener('scroll', this.editorToolBarToFixedWrapper, false)},data(){return {publishVisible: false,categorys: [],tags: [],articleForm: {id: '',title: '',summary: '',category: '',tags: [],editor: {value: '',ref: '',//保存mavonEditor实例  实际不该这样default_open: 'edit',toolbars: {bold: true, // 粗体italic: true, // 斜体header: true, // 标题underline: true, // 下划线strikethrough: true, // 中划线mark: true, // 标记superscript: true, // 上角标subscript: true, // 下角标quote: true, // 引用ol: true, // 有序列表ul: true, // 无序列表imagelink: true, // 图片链接code: true, // codefullscreen: true, // 全屏编辑readmodel: true, // 沉浸式阅读help: true, // 帮助undo: true, // 上一步redo: true, // 下一步trash: true, // 清空navigation: true, // 导航目录//subfield: true, // 单双栏模式preview: true, // 预览}}},rules: {summary: [{required: true, message: '请输入摘要', trigger: 'blur'},{max: 80, message: '不能大于80个字符', trigger: 'blur'}],category: [{required: true, message: '请选择文章分类', trigger: 'change'}],tags: [{type: 'array', required: true, message: '请选择标签', trigger: 'change'}]}}},computed: {title (){return '写文章'}},methods: {/*点击文章编辑时,获取文章详情*/getArticleById(id){let that = this;getArticleById(id).then(data =>{Object.assign(that.articleForm, data.data);that.articleForm.editor.value = data.data.body.content;let tags = this.articleForm.tags.map(function (item){return item.id;});this.articleForm.tags = tags}).catch(error =>{if (error !== 'error'){that.$message({type: 'error', message: '文章加载失败', showClose: true})}})},publishShow(){if (!this.articleForm.title){this.$message({message: '标题不能为空哦', type: 'warning', showClose: true})return}if (this.articleForm.title.length > 30){this.$message({message: '标题不能大于30个字符', type: 'warning', showClose: true})return}/*如果markdown编辑器内容为空*/if (!this.articleForm.editor.ref.d_render){this.$message({message: '内容不能为空哦', type: 'warning', showClose: true})return}/*点击发布,之后的对话框显示*/this.publishVisible = true;},/*文章发布*/publish(articleForm){let that = this;this.$refs[articleForm].validate((valid) =>{if (valid){let tags = this.articleForm.tags.map(function (item){return {id: item};});let article ={id: this.articleForm.id,title: this.articleForm.title,summary: this.articleForm.summary,category: this.articleForm.category,tags: tags,body: {content: this.articleForm.editor.value,contentHtml: this.articleForm.editor.ref.d_render}};this.publishVisible = false;let loading = this.$loading({lock: true,text: '发布中,请稍后...'});publishArticle(article,this.$store.state.token).then((data) =>{if(data.success){loading.close();that.$message({message: '发布成功啦', type: 'success', showClose: true})/*跳转到文章详情*/that.$router.push({path: `/view/${data.data.id}`})}else{that.$message({message: error, type: '发布文章失败:'+data.msg, showClose: true});}}).catch((error) =>{loading.close();if (error !== 'error'){that.$message({message: error, type: 'error', showClose: true});}});} else{return false;}});},cancel() {this.$confirm('文章将不会保存, 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.$router.push('/')})},/*获取所有标签以及分类*/getCategorysAndTags() {let that = thisgetAllCategorys().then(data =>{if(data.success){that.categorys = data.data}else{that.$message({type: 'error', message: '文章分类加载失败', showClose: true})}}).catch(error =>{if (error !== 'error'){that.$message({type: 'error', message: '文章分类加载失败', showClose: true})}})getAllTags().then(data =>{if(data.success){that.tags = data.data}else{that.$message({type: 'error', message: '标签加载失败', showClose: true})}}).catch(error =>{if (error !== 'error'){that.$message({type: 'error', message: '标签加载失败', showClose: true})}})},editorToolBarToFixed(){let toolbar = document.querySelector('.v-note-op');let curHeight = document.documentElement.scrollTop || document.body.scrollTop;if (curHeight >= 160){document.getElementById("placeholder").style.display = "block"; //bad  用计算属性较好toolbar.classList.add("me-write-toolbar-fixed");} else{document.getElementById("placeholder").style.display = "none";toolbar.classList.remove("me-write-toolbar-fixed");}}},components:{'base-header': BaseHeader,'markdown-editor': MarkdownEditor},//组件内的守卫 调整body的背景色beforeRouteEnter(to, from, next){window.document.body.style.backgroundColor = '#fff';next();},beforeRouteLeave(to, from, next){window.document.body.style.backgroundColor = '#f5f5f5';next();}}
</script><style>.el-header{position: fixed;z-index: 1024;min-width: 100%;box-shadow: 0 2px 3px hsla(0, 0%, 7%, .1), 0 0 0 1px hsla(0, 0%, 7%, .1);}.me-write-info{line-height: 60px;font-size: 18px;font-weight: 600;}.me-write-btn{margin-top: 10px;}.me-write-box{max-width: 700px;margin: 80px auto 0;}.me-write-main{padding: 0;}.me-write-title{}.me-write-input textarea{font-size: 32px;font-weight: 600;height: 20px;border: none;}.me-write-editor{min-height: 650px !important;}.me-header-left{margin-top: 10px;}.me-title img{max-height: 2.4rem;max-width: 100%;}.me-write-toolbar-fixed{position: fixed;width: 700px !important;top: 60px;}.v-note-op{box-shadow: none !important;}.auto-textarea-input, .auto-textarea-block{font-size: 18px !important;}
</style>

这里需要安装lodash插件:

npm i --save lodash

 main.js引用:

import lodash from 'lodash'
Object.defineProperty(Vue.prototype, '$_', { value: lodash })

baseHeader:

<template><el-header class="my-area"><el-row class="my-header"><!--头像--><el-col :span="4" class="my-header-left"><router-link to="/" class="my-title"><img src="../../assets/img/logo.png"/></router-link></el-col><el-col v-if="!simple" :span="16"><!--:router=true是否使用vue-router的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转--><el-menu :router=truemenu-trigger="click"active-text-color="#00aaff":default-active="activeIndex"mode="horizontal"><el-menu-item index="/"><i class="el-icon-tickets"></i>首页</el-menu-item><el-menu-item index="/category/all"><i class="el-icon-s-order"></i>文章分类</el-menu-item><el-menu-item index="/tag/all"><i class="el-icon-price-tag"></i>标签</el-menu-item><el-menu-item index="/archives"><i class="el-icon-chat-line-square"></i>文章归档</el-menu-item><!--offset可以指定偏移数--><el-col :span="4" :offset="4"><el-menu-item index="/write"><i class="el-icon-edit"></i>写文章</el-menu-item></el-col></el-menu></el-col><template v-else><slot></slot></template><el-col :span="4"><el-menu :router=truemenu-trigger="click"mode="horizontal"active-text-color="#00aaff"><template v-if="!user.login"><el-menu-item index="/login"><el-button type="text">登录</el-button></el-menu-item><el-menu-item index="/register"><el-button type="text">注册</el-button></el-menu-item></template><template v-else><el-submenu index><template slot="title"><img class="my-header-picture" :src="user.avatar"/></template><el-menu-item index @click="logout"><i class="el-icon-back"></i>退出</el-menu-item></el-submenu></template></el-menu></el-col></el-row></el-header>
</template><script>export default {name: 'BaseHeader',props: {activeIndex: String,//选中哪个menu进行下方条形的一个显示simple: {type: Boolean,default: false}},computed: {user(){let login = this.$store.state.account.length !== 0;let avatar = this.$store.state.avatar;return{login,avatar}}},methods: {logout(){this.$store.dispatch("logout").then((res)=>{this.$router.push({path:"/login"});this.$message({message:"已退出账户,请重新登录",type:"success",showClose:true});}).catch((error)=>{this.$message({message:error,type:"error",showClose:true});})},}}
</script><style>/*登录、注册*/.el-button{color: #00aaff;}/*body*/.el-header{background-color: white;position: fixed;z-index: 1024;min-width: 100%;box-shadow: 0 1px 2px hsla(0, 0%, 7%, .1), 0 0 0 0px hsla(0, 0%, 7%, .1);}/*头像*/.my-title{margin-top: 10px;font-size: 24px;}.my-header-left{margin-top: 10px;}/*左上角头像*/.my-title img{max-height: 2.5rem;max-width: 100%;}.my-header-picture{width: 36px;height: 36px;border: 1px solid #ddd;border-radius: 50%;vertical-align: middle;background-color: #00aaff;}
</style>

markdown需要调用upload接口,将图片上传到七牛云

import request from '@/request'
/*发布文章时,有可能在markdown会上传图片*/
export function upload(formdata) {return request({headers: {'Content-Type': 'multipart/form-data'},url: '/upload',method: 'post',data: formdata})
}

markdown组件:

<template><mavon-editorclass="my-editor"ref="md"v-model="editor.value"@imgAdd="imgAdd"v-bind="editor"></mavon-editor>
</template><script>import {mavonEditor} from 'mavon-editor'import 'mavon-editor/dist/css/index.css'import {upload} from '@/api/upload'export default {name: 'MarkdownEditor',props: {editor: Object},data() {return {}},mounted() {this.$set(this.editor, 'ref', this.$refs.md)},methods: {/*图片上传*/imgAdd(pos, $file){let that = thislet formData = new FormData();formData.append('image', $file);upload(formData).then(res =>{// 第二步.将返回的url替换到文本原位置![...](./0) -> ![...](url)if (res.data.success){that.$refs.md.$img2Url(pos, res.data.data);} else {that.$message({message: res.data.msg, type: 'error', showClose: true})}}).catch(err => {that.$message({message: err, type: 'error', showClose: true});})}},components: {mavonEditor}}
</script>
<style scoped>.my-editor{z-index: 6 !important;}.v-note-wrapper.fullscreen{top: 60px !important}
</style>


http://chatgpt.dhexx.cn/article/QKGtNZk1.shtml

相关文章

Python爬取网上文章并发表到微信公众号

前言 话说懒惰是人类进步的原动力&#xff0c;古人诚不欺我。最近在折腾一个微信公众号&#xff0c;开始的时候在网上找一些资源然后进行二次创作然后发表到微信公众号&#xff0c;但是这就要自己先把里面的图片下载下来然后文字也复制过来然后再慢慢的上传到微信公众号&#…

如何用CSDN发布文章

CSDN怎么写博客&#xff1f; 1、首先打开CSDN官网&#xff0c;进行注册或者登录 2、登录后点击右上角的创作中心 3、进入以后点击左上角的发布 4、可以开始写入你要写的内容&#xff0c;先写入标题 5、然后再写你要写的内容&#xff0c;左侧写内容&#xff0c;右侧可以预览&a…

Hexo博客发表文章、草稿、添加分类和标签

写在前面 本文主要写了hexo的配置&#xff0c;关于博客标题这些配置HEXO已经有了很详细的介绍了&#xff0c;这里不再赘述&#xff0c;本文主要记录一些我个人认为小白比较容易有疑问的地方&#xff0c;也就是博客的主要功能&#xff0c;发表文章、添加文章分类和标签。文章可…

Springboot+Vue实现发表文章功能

点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐] 效果图 前端编辑页面 文章列表页面 文章详情页面 环境介绍 JDK&#xff1a;1.8 数据库&#xff1a;Mysql5.6 前端&#xff1a;Vue 后端&#xff1a;SpringBoot 核心代码介绍 AtricleCtrle.class RestController RequestMa…

使用hexo发布文章

前言: 如何用指令去创建一篇文章,然后发布? .我们先来看一下hexo的目录结构,了解每个目录的作用,这将让我们对hexo的运行原理有一个大概的认识,对于我们后面美化主题是有帮助的, 然后再来创建文章,并发布到本地服务器,最后查看效果. 一、Hexo的目录分析: &#xff11;&#…

微信公众号发布

微信公众号如何发文章 输入微信公众号 打开百度浏览器&#xff0c;搜索栏输入微信公众号&#xff0c;点击百度一下。 打开微信公众平台 页面显示搜索结果&#xff0c;页面选择微信公众平台官方链接点击打开。 扫一扫二维码 进入微信公众平台页面&#xff0c;使用你的微信扫一扫…

软件测试培训:等价类划分法概述

等价类划分法是一种常用的黑盒测试方法&#xff0c;它主张从大量数据中选择一部分数据用于测试&#xff0c;即尽可能使用最少的测试用例覆盖最多的数据&#xff0c;以发现更多的软件缺陷。 一个程序可以有多个输入&#xff0c;等价类划分就是将这些数据按照输入需求进行分类&am…

等价类划分法+边界值法

一、测试用例&#xff08;案例&#xff09; 1.1 定义&#xff1a; ​ 是在测试执行之前&#xff0c;由测试人员编写的指导测试过程的重要文档&#xff0c;主要包括&#xff1a;用例编号、测试目的、测试步骤&#xff08;用例描述&#xff09;&#xff0c;预期结果 1.2 介绍编…

什么是等价类划分法?

1.等价类划分法&#xff1f; 等价类划分是把所有可能输入的数据分为若干个区域&#xff0c;然后从每个区域中取少量有代表性的数据进行测试即可。 等价类 &#xff1a;何为等价类&#xff0c;某个输入域的集合&#xff0c;在这个集合中每个输入条件都是等效的。 2.分类 一般…

等价类划分法实验

一、使用等价类划分法分析三角形问题 要求一&#xff1a;需包含有效等价类及无效等价类划分表格 以及 测试用例表格 要求二&#xff1a;代码实现 实现 方式一&#xff1a;设计 三个输入框 一个判断按钮 点击按钮后显示结果 实现方式二&#xff1a;Java控制台进行测试判断【本实…

解决typora beta版本过期提示

现在beta版的typora打开都会有这个弹窗提示&#xff0c;想要把弹窗提示解决其实很简单&#xff0c;只要按照下面这个办法解决就可以了。 winr打开运行窗口&#xff0c;输入regedit&#xff0c;点确定打开注册表&#xff0c;依次展开计算机\HKEY_CURRENT_USER\SOFTWARE\Typora&…

Beta版本发布说明

2 Beta版本发布说明 2.1 列出这一版本的功能 Beta版本基于Alpha版本&#xff08;实现博主登录、发布博文、设置博客、搜索博文、点击标签显示相应博文、点击分类显示相应博文、留言功能&#xff09;上&#xff0c;主要新增以下几个功能&#xff1a; Message页面的信息推送功能、…

Elasticsearch5.0 beta版本安装错误

转载请注明出处&#xff1a;http://blog.csdn.net/gamer_gyt 博主微博&#xff1a;http://weibo.com/234654758 Github&#xff1a;https://github.com/thinkgamer 写在前边的话 elasticsearch的alpha版本早已经在github上了&#xff0c;但是beta版本却是最近才正式发布&#…

【AIGC】Photoshop AI Beta版本安装使用(永久免费)

AIGC 大爆发 Adobe近日宣布&#xff0c;Photoshop&#xff08;测试版&#xff09;应用程序发布了生成式AI绘图&#xff0c;这是世界上第一个创意和设计工作流程的副驾驶&#xff0c;为用户提供了一种神奇的新工作方式。生成式AI绘图由Adobe Firefly提供支持&#xff0c;Adobe的…

Beta版本软件使用说明

北京航空航天大学计算机学院 远航1617 小组 产品版本&#xff1a; Beta版本 产品名称&#xff1a;Crawling is going on 文档作者&#xff1a;杨帆 文档日期&#xff1a;2013/12/24 1. 引言 1.1 编写目的 编写本使用说明的目的是充分叙述本软件所能实现的功能及其…

Beta版本测试报告以及Beta版本发布说明

Beta版本测试报告 请根据团队项目中软件的需求文档、功能说明、系统设计和Beta阶段的计划安排&#xff0c;写出软件的测试过程和测试结果&#xff0c;并回答下述问题。 在测试过程中总共发现了多少bug&#xff1f;每个类别的bug分别为多少个&#xff1f;bug的分类&#xff1a; …

Beta版本测试报告

新发现的问题&战略调整&#xff1a; 这里的问题主要包含两种&#xff1a; 优化问题和不影响整体使用的bug&#xff0c;主要针对即时聊天以及UI交互部分&#xff1b;我们安排六位同学两两组队&#xff0c;在一周时间内分别对产品进行覆盖性的体验测试&#xff0c;提出了以…

微软发布 Windows 11 首个 Beta 版本

近日&#xff0c;微软向开发频道发布了 Windows 11 Insider Preview Build 22000.100&#xff0c;在没有发现重大问题之后&#xff0c;微软现在又向更稳定的 Beta 频道发布了同样的版本&#xff0c;这也是 Windows 11 首个 Beta 频道的预览版。微软建议那些想尝试 Windows 11 版…

软件版本号讲解:什么是Alpha, Beta, RC,Release

1. 软件版本阶段说明 Alpha版: 此版本表示该软件在此阶段主要是以实现软件功能为主&#xff0c;通常只在软件开发者内部交流&#xff0c;一般而言&#xff0c;该版本软件的Bug较多&#xff0c;需要继续修改。Beta版: 该版本相对于α版已有了很大的改进&#xff0c;消除了严重的…

WhiteHole Base beta版本正式发布!

体验 当前版本为基础测试版本&#xff0c;测试效果可以前往演示视频查看&#xff1a;https://www.bilibili.com/video/BV18Y411D7sA/?spm_id_from333.999.0.0&vd_source641e71dfd1a118fb834c4a5d156688d5 在线体验地址为&#xff1a; http://47.100.239.95 数据将保存~ …