随笔 - 77  文章 - 0  评论 - 0  阅读 - 21363 

在vue中引入集成markdown富文本编辑器

这里我们使用 mavonEditor,链接:https://github.com/hinesboy/mavonEditor

安装

cd renran_pc
npm install mavon-editor --save

在main.js中注册编辑器组件

    import mavonEditor from 'mavon-editor'
   import 'mavon-editor/dist/css/index.css'
// 注册mavon-editor组件
   Vue.use(mavonEditor);
   new Vue({
       'el': '#main'
  })

 

写文章页面

创建Write.vue组件,提供给用户编写文章

<template>
 <div class="write">
   <div class="_2v5v5">
     <div class="_3zibT"><a href="/">回首页</a></div>
     <div class="_1iZMb">
       <div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
       <div class="_2G97m">
         <form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
           <input type="text" placeholder="请输入文集名..." name="name" class="_1CtV4">
           <button type="submit" class="dwU8Q _3zXcJ _3QfkW"><span>提 交</span></button>
           <button type="button" class="vIzwB _3zXcJ" @click="collection_form=false"><span>取 消</span></button>
         </form>
       </div>
     </div>
     <ul class="_3MbJ4 _3t059">
       <li class="_3DM7w _31PCv" title="日记本">
         <div class="_3P4JX _2VLy-">
           <i class="fa fa-gear"></i>
           <span>
             <ul class="_2V8zt _3FcHm _2w9pn" :class="true?'':'NvfK4'">
               <li class="_2po2r cRfUr" title="">
                 <span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
               </li>
               <li class="_2po2r cRfUr" title="">
                 <span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
               </li>
             </ul>
           </span>
         </div>
         <span>日记本</span>
       </li>
       <li class="_3DM7w" title="随笔"><span>随笔</span></li>
     </ul>
     <div style="height: 50px;"></div>
     <div role="button" class="h-5Am">
       <span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
       <span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
     </div>
   </div>
   <div class="rQQG7">
     <div class="_3revO _2mnPN">
       <div class="_3br9T">
         <div>
           <div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
           <ul class="_2TxA-">
             <li class="_25Ilv _33nt7" title="ABC">
               <i class="_13kgp _2m93u"></i>
               <div class="_3P4JX poOXI">
                 <i class="fa fa-gear"></i>
                 <span>
                   <ul class="_2V8zt _3FcHm _2w9pn">
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
                     <li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
                     <li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
                       <div class="_3x4X_">
                         <ul class="_2KzJx oGKRI _3DXDE _2w9pn">
                           <li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
                         </ul>
                       </div>
                     </span>
                     </li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
                   </ul>
                 </span>
               </div>
               <span class="NariC">ABC</span>
               <span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

题目:企业发放的奖金根据利润提成</span>
               <span class="_29C-V">字数:905</span>
             </li>
             <li class="_25Ilv" title="2020-01-12">
               <i class="_13kgp"></i>
               <span class="NariC">2020-01-12</span>
               <span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

题目:企业发放的奖金根据利润提成</span>
             </li>
           </ul>
           <div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
         </div>
       </div>
     </div>
     <input type="text" class="_24i7u" value="2020-01-12">
     <div id="editor">
       <mavon-editor
         style="height: 100%"
         v-model="editorContent"
         :ishljs="true"
         ref=md
         @imgAdd="imgAdd"
         @imgDel="imgDel"
       ></mavon-editor>
     </div>
   </div>
 </div>
</template>
<script>
 import { mavonEditor } from 'mavon-editor'
 import 'mavon-editor/dist/css/index.css'
   export default {
       name: "Write",
       data(){
           return {
               editorContent:"",
               img_file:[],
               collection_form:false,
          }
      },
       watch:{
           editorContent(){
               console.log(this.editorContent)
          }
      },
       mounted(){
           document.querySelector("#editor").style.height = document.documentElement.clientHeight-document.querySelector("._24i7u").clientHeight+"px";
      },
       components: {
         mavonEditor
      },
       methods:{
         // 绑定@imgAdd event
         imgAdd(pos, $file){
             // 添加文件
        },
         imgDel(pos) {
             // 删除文件
        }
      }
  }
</script>

路由代码:

// 。。。
import Write from "@/components/Write"


export default new Router({
 mode: "history",
 routes: [
    // ....
    {
      name:"Write",
      path:"/write",
      component: Write,
    },
]
})

在 Header.vue提供跳转链接

<router-link class="btn write-btn" target="_blank" to="/writer"><img class="icon-write" src="/static/image/write.svg">写文章</router-link>

 

完善富文本编辑器添加图片到服务端功能

服务端实现上传图片的API接口

视图代码:

from rest_framework.generics import CreateAPIView
from .models import ArticleImage
from .serializers import ArticleImageModelSerializer
class ImageAPIView(CreateAPIView):
   queryset = ArticleImage.objects.all()
   serializer_class = ArticleImageModelSerializer

序列化器:

from rest_framework import serializers
from .models import ArticleImage
class ArticleImageModelSerializer(serializers.ModelSerializer):
   class Meta:
       model = ArticleImage
       fields = ("image",)

   def create(self, validated_data):
       instance = ArticleImage.objects.create(image=validated_data.get("image"),group=1)
       return instance

路由代码:

from django.urls import path
from . import views
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
   path("uploadimg/", views.ImageAPIView.as_view()),
]

客户端实现在富文本编辑器中用户添加图片时直接上传文件到服务端FastDFS系统。

<template>
 <div class="write">
   <div class="_2v5v5">
     <div class="_3zibT"><a href="/">回首页</a></div>
     <div class="_1iZMb">
       <div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
       <div class="_2G97m">
         <form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
           <input type="text" placeholder="请输入文集名..." name="name" class="_1CtV4">
           <button type="submit" class="dwU8Q _3zXcJ _3QfkW"><span>提 交</span></button>
           <button type="button" class="vIzwB _3zXcJ" @click="collection_form=false"><span>取 消</span></button>
         </form>
       </div>
     </div>
     <ul class="_3MbJ4 _3t059">
       <li class="_3DM7w _31PCv" title="日记本">
         <div class="_3P4JX _2VLy-">
           <i class="fa fa-gear"></i>
           <span>
             <ul class="_2V8zt _3FcHm _2w9pn" :class="true?'':'NvfK4'">
               <li class="_2po2r cRfUr" title="">
                 <span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
               </li>
               <li class="_2po2r cRfUr" title="">
                 <span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
               </li>
             </ul>
           </span>
         </div>
         <span>日记本</span>
       </li>
       <li class="_3DM7w" title="随笔"><span>随笔</span></li>
     </ul>
     <div style="height: 50px;"></div>
     <div role="button" class="h-5Am">
       <span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
       <span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
     </div>
   </div>
   <div class="rQQG7">
     <div class="_3revO _2mnPN">
       <div class="_3br9T">
         <div>
           <div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
           <ul class="_2TxA-">
             <li class="_25Ilv _33nt7" title="ABC">
               <i class="_13kgp _2m93u"></i>
               <div class="_3P4JX poOXI">
                 <i class="fa fa-gear"></i>
                 <span>
                   <ul class="_2V8zt _3FcHm _2w9pn">
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
                     <li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
                     <li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
                       <div class="_3x4X_">
                         <ul class="_2KzJx oGKRI _3DXDE _2w9pn">
                           <li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
                         </ul>
                       </div>
                     </span>
                     </li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
                   </ul>
                 </span>
               </div>
               <span class="NariC">ABC</span>
               <span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

题目:企业发放的奖金根据利润提成</span>
               <span class="_29C-V">字数:905</span>
             </li>
             <li class="_25Ilv" title="2020-01-12">
               <i class="_13kgp"></i>
               <span class="NariC">2020-01-12</span>
               <span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

题目:企业发放的奖金根据利润提成</span>
             </li>
           </ul>
           <div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
         </div>
       </div>
     </div>
     <input type="text" class="_24i7u" value="2020-01-12">
     <div id="editor">
       <mavon-editor
         style="height: 100%"
         v-model="editorContent"
         :ishljs="true"
         ref=md
         @imgAdd="imgAdd"
         @imgDel="imgDel"
       ></mavon-editor>
     </div>
   </div>
 </div>
</template>
<script>
 import { mavonEditor } from 'mavon-editor'
 import 'mavon-editor/dist/css/index.css'
   export default {
       name: "Write",
       data(){
           return {
               editorContent:"",
               img_file:[],
               collection_form:false,
          }
      },
       watch:{
           editorContent(){
               console.log(this.editorContent)
          }
      },
       mounted(){
           document.querySelector("#editor").style.height = document.documentElement.clientHeight-document.querySelector("._24i7u").clientHeight+"px";
      },
       components: {
         mavonEditor
      },
       methods:{
         // 绑定@imgAdd event
         imgAdd(pos, $file){
             // 第一步.将图片上传到服务器.
             var formdata = new FormData();
             formdata.append('image', $file);
             this.img_file[pos] = $file;
             this.$axios.post(`${this.$settings.Host}/article/uploadimg/`, formdata,{
                 'Content-Type': 'multipart/form-data'
            }).then((res) => {
                 let _res = res.data;
                 // 第二步.将返回的url替换到文本原位置![...](0) -> ![...](url)
                 this.$refs.md.$img2Url(pos, _res.image);
            });
        },
         imgDel(pos) {
             delete this.img_file[pos];
        }
      }
  }
</script>

 

添加文集

视图代码:

from .models import ArticleCollection
from .serializers import ArticleCollectionModelSerializer
from rest_framework.permissions import IsAuthenticated
class CollectionAPIView(CreateAPIView):
   """添加文集"""
   queryset = ArticleCollection.objects.all()
   serializer_class = ArticleCollectionModelSerializer
   permission_classes = [IsAuthenticated]

序列化器,代码:

from rest_framework import serializers
from .models import ArticleImage
class ArticleImageModelSerializer(serializers.ModelSerializer):
   class Meta:
       model = ArticleImage
       fields = ("image",)

   def create(self, validated_data):
       instance = ArticleImage.objects.create(image=validated_data.get("image"),group=1)
       return instance

from .models import ArticleCollection
class ArticleCollectionModelSerializer(serializers.ModelSerializer):
   class Meta:
       model = ArticleCollection
       fields = ["name"]

   def validate(self, attrs):
       # 验证当前用户的文集是否同名
       user = self.context["request"].user
       name = attrs.get("name")
       try:
           ArticleCollection.objects.get(user=user,name=name)
           raise serializers.ValidationError("对不起,当前文集您已经创建了!")
       except ArticleCollection.DoesNotExist:
           pass

       return attrs

   def create(self, validated_data):
       name = validated_data.get("name")
       try:
           collection = ArticleCollection.objects.create(user=user, name=name)
       except:
           raise serializers.ValidationError("对不起,当前文集您已经创建了!")

       return collection

路由代码:

from django.urls import path
from . import views
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
   path("uploadimg/", views.ImageAPIView.as_view()),
   path("collection/", views.CollectionAPIView.as_view()),
]

客户端发起请求添加文集

<template>
 <div class="write">
   <div class="_2v5v5">
     <div class="_3zibT"><a href="/">回首页</a></div>
     <div class="_1iZMb">
       <div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
       <div class="_2G97m">
         <form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
           <input type="text" placeholder="请输入文集名..." v-model="collection_name" class="_1CtV4">
           <button type="submit" class="dwU8Q _3zXcJ _3QfkW" @click.prevent="add_collection"><span>提 交</span></button>
           <button type="button" class="vIzwB _3zXcJ" @click="collection_form=false"><span>取 消</span></button>
         </form>
       </div>
     </div>
     <ul class="_3MbJ4 _3t059">
       <li class="_3DM7w _31PCv" title="日记本">
         <div class="_3P4JX _2VLy-">
           <i class="fa fa-gear"></i>
           <span>
             <ul class="_2V8zt _3FcHm _2w9pn" :class="true?'':'NvfK4'">
               <li class="_2po2r cRfUr" title="">
                 <span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
               </li>
               <li class="_2po2r cRfUr" title="">
                 <span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
               </li>
             </ul>
           </span>
         </div>
         <span>日记本</span>
       </li>
       <li class="_3DM7w" title="随笔"><span>随笔</span></li>
     </ul>
     <div style="height: 50px;"></div>
     <div role="button" class="h-5Am">
       <span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
       <span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
     </div>
   </div>
   <div class="rQQG7">
     <div class="_3revO _2mnPN">
       <div class="_3br9T">
         <div>
           <div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
           <ul class="_2TxA-">
             <li class="_25Ilv _33nt7" title="ABC">
               <i class="_13kgp _2m93u"></i>
               <div class="_3P4JX poOXI">
                 <i class="fa fa-gear"></i>
                 <span>
                   <ul class="_2V8zt _3FcHm _2w9pn">
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
                     <li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
                     <li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
                       <div class="_3x4X_">
                         <ul class="_2KzJx oGKRI _3DXDE _2w9pn">
                           <li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
                         </ul>
                       </div>
                     </span>
                     </li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
                     <li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
                   </ul>
                 </span>
               </div>
               <span class="NariC">ABC</span>
               <span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

题目:企业发放的奖金根据利润提成</span>
               <span class="_29C-V">字数:905</span>
             </li>
             <li class="_25Ilv" title="2020-01-12">
               <i class="_13kgp"></i>
               <span class="NariC">2020-01-12</span>
               <span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

题目:企业发放的奖金根据利润提成</span>
             </li>
           </ul>
           <div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
         </div>
       </div>
     </div>
     <input type="text" class="_24i7u" value="2020-01-12">
     <div id="editor">
       <mavon-editor
         style="height: 100%"
         v-model="editorContent"
         :ishljs="true"
         ref=md
         @imgAdd="imgAdd"
         @imgDel="imgDel"
       ></mavon-editor>
     </div>
   </div>
 </div>
</template>
<script>
 import { mavonEditor } from 'mavon-editor'
 import 'mavon-editor/dist/css/index.css'
   export default {
       name: "Write",
       data(){
           return {
               collection_name: "",
               editorContent:"",
               img_file:[],
               collection_form:false,
          }
      },
       watch:{
           editorContent(){
               console.log(this.editorContent)
          }
      },
       mounted(){
           document.querySelector("#editor").style.height = document.documentElement.clientHeight-document.querySelector("._24i7u").clientHeight+"px";
      },
       components: {
         mavonEditor
      },
       methods:{
         // 绑定@imgAdd event
         imgAdd(pos, $file){
             // 第一步.将图片上传到服务器.
             var formdata = new FormData();
             formdata.append('image', $file);
             this.img_file[pos] = $file;
             this.$axios.post(`${this.$settings.Host}/article/uploadimg/`, formdata,{
                 'Content-Type': 'multipart/form-data'
            }).then((res) => {
                 let _res = res.data;
                 // 第二步.将返回的url替换到文本原位置![...](0) -> ![...](url)
                 this.$refs.md.$img2Url(pos, _res.image);
            });
        },
         imgDel(pos) {
             delete this.img_file[pos];
        },
         add_collection(){
             if(this.collection_name.length<1){
                 this.$message.error("文集名称不能为空!");
            }
             let token = this.$settings.get_login_user();
             if(!token){
                 this.$message.error("对不起,请登录后再继续操作!");
                 return false;
            }

             this.$axios.post(`${this.$settings.Host}/article/collection/`,{
                 name: this.collection_name,
            },{
                 headers:{
                     Authorization: "jwt " + token,
                }
            }).then(response=>{
                 this.$message.success("添加文集成功!");
            }).catch(error=>{
                 this.$message.error("添加文集失败!");
            });
        }
      }
  }
</script>

 

posted on   rider_yang  阅读(232)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示