vue-quill-editor 富文本编辑器上传视频

2023-10-27

插入视频

富文本编辑器中插入视频思路:劫持原来的视频上传事件,然后,自定义上传组件将视频上传到服务器,服务器返回一个视频链接,再插入到富文本编辑器中。

封装富文本编辑器组件 quill.vue

<!--富文本编辑器-->
<template>
  <div class="rich-text-editor-container" v-loading="loading">
    <quill-editor :content="content" :options="editorOptions" class="ql-editor" ref="myQuillEditor" @change="onEditorChange($event)">
    </quill-editor>
    <!--视频上传弹窗-->
    <div>
      <el-dialog :close-on-click-modal="false" width="50%" style="margin-top: 1px" title="视频上传" :visible.sync="videoForm.show" append-to-body>
        <el-tabs v-model="videoForm.activeName">
          <el-tab-pane label="添加视频链接" name="first">
            <el-input v-model="videoForm.videoLink" placeholder="请输入视频链接" clearable></el-input>
            <el-button type="primary" size="small" style="margin: 20px 0px 0px 0px " @click="insertVideoLink(videoForm.videoLink)">确认
            </el-button>
          </el-tab-pane>
          <el-tab-pane label="本地视频上传" name="second">
            <el-upload v-loading="loading" style="text-align: center;" drag :action="uploadVideoConfig.uploadUrl" accept="video/*" :name="uploadVideoConfig.name" :before-upload="onBeforeUploadVideo" :on-success="onSuccessVideo" :on-error="onErrorVideo" :multiple="false">
              <i class="el-icon-upload"></i>
              <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
              <div class="el-upload__tip" slot="tip">只能上传MP4文件,且不超过{{uploadVideoConfig.maxSize}}M</div>
            </el-upload>
          </el-tab-pane>
        </el-tabs>
      </el-dialog>
    </div>
  </div>
</template>
<script>
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'

// 工具栏
const toolbarOptions = [
  ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
  ["blockquote", "code-block"], // 引用  代码块
  [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
  [{ indent: "-1" }, { indent: "+1" }], // 缩进
  [{ size: ["small", false, "large", "huge"] }], // 字体大小
  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
  [{ align: [] }], // 对齐方式
  ["clean"], // 清除文本格式
  ['video'] // 视频
]
export default {
  name: 'RichTextEditor',
  components: {
    quillEditor
  },
  props: {
    /* 编辑器的内容 */
    content: { // 返回的html片段
      type: String,
      default: ''
    },
    // 视频上传配置
    uploadVideoConfig: {
      type: Object,
      default () {
        return {
          uploadUrl: '', // 上传地址
          maxSize: 10, // 图片上传大小限制,默认不超过2M
          name: 'Filedata' // 图片上传字段
        }
      }
    }
  },
  data () {
    let _self = this;
    return {
      loading: false, // 加载loading
      editorOptions: {
        placeholder: '',
        theme: 'snow', // or 'bubble'
        modules: {
          toolbar: {
            container: toolbarOptions, // 工具栏
            handlers: {
              'video': () => {
                // 覆盖默认的上传视频,点击视频图标,显示弹窗
                _self.videoForm.show = true
              }
            }
          }
        }
      },
      // 视频上传变量
      videoForm: {
        show: false, // 显示插入视频链接弹框的标识
        videoLink: '',
        activeName: 'first'
      }
    }
  },
  mounted () {
  },
  methods: {
    // 文本编辑
    onEditorChange ({ quill, html, text }) {
      console.log('editor changed:', quill, html, text)
      console.log('html.replace(/<[^>]*>|/g:', html.replace(/<[^>]*>|/g))
      this.$emit('update:content', html)
      this.$emit('change', html)
    },
    hideLoading () {
      this.loading = false
    },
    /** --------- 视频上传相关 start ---------  */
    insertVideoLink (videoLink) {
      if (!videoLink) return this.$message.error('视频地址不能为空!')
      this.videoForm.show = false
      let quill = this.$refs['myQuillEditor'].quill
      // 获取富文本
      let range = quill.getSelection()
      // 获取光标位置:当编辑器中没有输入文本时,这里获取到的 range 为 null
      let index = range ? range.index : 0
      // 在光标所在位置 插入视频
      quill.insertEmbed(index, 'video', videoLink)
      // 调整光标到最后
      quill.setSelection(index + 1)
    },
    // el-文件上传组件
    onBeforeUploadVideo (file) {
      this.loading = true
      let acceptArr = ['video/mp4']
      const isVideo = acceptArr.includes(file.type)
      const isLt1M = file.size / 1024 / 1024 < this.uploadVideoConfig.maxSize
      if (!isVideo) {
        this.hideLoading()
        this.$message.error('只能上传mp4格式文件!')
      }
      if (!isLt1M) {
        this.hideLoading()
        this.$message.error(`上传文件大小不能超过 ${this.uploadVideoConfig.maxSize}MB!`)
      }
      return isLt1M && isVideo
    },
    // 文件上传成功时的钩子
    onSuccessVideo (res) {
      this.hideLoading()
      if (res.code === '100') {
        this.insertVideoLink(res.url)
      } else {
        this.$message.error(res.desc)
      }
    },
    // 文件上传失败时的钩子
    onErrorVideo () {
      this.hideLoading()
      this.$message.error('上传失败')
    },
    /**--------- 视频上传相关 end --------- */
  }
}
</script>
<style  lang='less'>
.rich-text-editor-container .ql-container {
  height: 300px;
}

.rich-text-editor-container .ql-editor {
  padding: 0;
}

.rich-text-editor-container .ql-tooltip {
  left: 5px !important;
}
</style>

页面使用封装的富文本编辑器组件,新建 add.vue

<template>
  <div>
    <editor :content="content" v-model="content" :height="480" />
  </div>
</template>

<script>
import Editor from "./quill";

export default {
  components: {
    Editor
  },
  data() {
    return {
      content: ""
    };
  }
};
</script>

设置工具栏中文标题

新建 quill-title.js

// 给工具栏设置title
const titleConfig = {
  'ql-bold': '加粗',
  'ql-font': '字体',
  'ql-code': '插入代码',
  'ql-italic': '斜体',
  'ql-link': '添加链接',
  'ql-color': '字体颜色',
  'ql-background': '背景颜色',
  'ql-size': '字体大小',
  'ql-strike': '删除线',
  'ql-script': '上标/下标',
  'ql-underline': '下划线',
  'ql-blockquote': '引用',
  'ql-header': '标题',
  'ql-indent': '缩进',
  'ql-list': '列表',
  'ql-align': '文本对齐',
  'ql-direction': '文本方向',
  'ql-code-block': '代码块',
  'ql-formula': '公式',
  'ql-image': '图片',
  'ql-video': '视频',
  'ql-clean': '清除字体样式'
}

export function setQuillTitle () {
  const oToolBar = document.querySelector('.ql-toolbar')
  const aButton = oToolBar.querySelectorAll('button')
  const aSelect = oToolBar.querySelectorAll('select')
  aButton.forEach(function (item) {
    if (item.className === 'ql-script') {
      item.value === 'sub' ? item.title = '下标' : item.title = '上标'
    } else if (item.className === 'ql-indent') {
      item.value === '+1' ? item.title = '向右缩进' : item.title = '向左缩进'
    } else {
      item.title = titleConfig[item.className]
    }
  })
  // 字体颜色和字体背景特殊处理,两个在相同的盒子
  aSelect.forEach(function (item) {
    if (item.className.indexOf('ql-background') > -1) {
      item.previousSibling.title = titleConfig['ql-background']
    } else if (item.className.indexOf('ql-color') > -1) {
      item.previousSibling.title = titleConfig['ql-color']
    } else {
      item.parentNode.title = titleConfig[item.className]
    }
  })
}

修改 quill.vue 文件:

// 设置title
import { setQuillTitle } from './quill-title.js'

mounted 中调用 setQuillTitle 方法:

  mounted () {
    // 初始给编辑器设置title
    setQuillTitle()
  }

但是,以上富文本编辑器有一个问题:就是 vue-quill-editor 默认是以 iframe 保存的,插入到编辑器中的标签是 <iframe class=\"ql-video\" frameborder=\"0\" allowfullscreen=\"true\" src=\"https://xxx\"></iframe>,如下图:
在这里插入图片描述

但是,实际使用过程中,需要的是插入一个 video 标签。

修改视频 <iframe> 标签为 <video>

新建 quill-video.js

import { Quill } from "vue-quill-editor";
// 源码中是import直接倒入,这里要用Quill.import引入
const BlockEmbed = Quill.import('blots/block/embed')
const Link = Quill.import('formats/link')

const ATTRIBUTES = ['height', 'width']

class Video extends BlockEmbed {
  static create(value) {
    const node = super.create(value)
    // 添加video标签所需的属性
    node.setAttribute('controls', 'controls')
    node.setAttribute('type', 'video/mp4')
    node.setAttribute('src', this.sanitize(value))
    return node
  }

  static formats(domNode) {
    return ATTRIBUTES.reduce((formats, attribute) => {
      if (domNode.hasAttribute(attribute)) {
        formats[attribute] = domNode.getAttribute(attribute)
      }
      return formats
    }, {})
  }

  static sanitize(url) {
    return Link.sanitize(url) // eslint-disable-line import/no-named-as-default-member
  }

  static value(domNode) {
    return domNode.getAttribute('src')
  }

  format(name, value) {
    if (ATTRIBUTES.indexOf(name) > -1) {
      if (value) {
        this.domNode.setAttribute(name, value)
      } else {
        this.domNode.removeAttribute(name)
      }
    } else {
      super.format(name, value)
    }
  }

  html() {
    const { video } = this.value()
    return `<a href="${video}">${video}</a>`
  }
}
Video.blotName = 'video' // 这里不用改,楼主不用iframe,直接替换掉原来,如果需要也可以保留原来的,这里用个新的blot
Video.className = 'ql-video'
Video.tagName = 'video' // 用video标签替换iframe

export default Video

修改 quill.vue 文件:

import { quillEditor, Quill } from 'vue-quill-editor'
// 这里引入修改过的video模块并注册
import Video from './video'
Quill.register(Video, true)

如下图:
在这里插入图片描述

在页面可以看到,插入到编辑器中的标签是 <video class=\"ql-video\" controls=\"controls\" type=\"video/mp4\" src=\"xxx\"></video>,如下图:
在这里插入图片描述

设置video 标签自定义属性

有时候,还需要给 video 标签添加一些自定义的属性:修改 quill-video.js 文件:
在这里插入图片描述

修改 quill.vue 文件:
在这里插入图片描述

这样,就给 video 标签加上了自定义属性:<video class=\"ql-video\" controls=\"controls\" playsinline=\"true\" webkit-playsinline=\"true\" type=\"video/mp4\" poster=\"https://xxx\" src=\"https://xxx\"></video>

PS:以此类推,也可以给 video 标签添加一些其它属性,例如 width,height 等等啦,只需要照着上面的方式修改对应地方即可。

页面效果:
在这里插入图片描述

完整 quill.vue 代码:

<!--富文本编辑器-->
<template>
  <div class="rich-text-editor-container" v-loading="loading">
    <quill-editor :content="content" :options="editorOptions" class="ql-editor" ref="myQuillEditor" @change="onEditorChange($event)">
    </quill-editor>
    <!--视频上传弹窗-->
    <div>
      <el-dialog :close-on-click-modal="false" width="50%" style="margin-top: 1px" title="视频上传" :visible.sync="videoForm.show" append-to-body>
        <el-tabs v-model="videoForm.activeName">
          <el-tab-pane label="添加视频链接" name="first">
            <el-input v-model="videoForm.videoLink" placeholder="请输入视频链接" clearable></el-input>
            <el-button type="primary" size="small" style="margin: 20px 0px 0px 0px " @click="insertVideoLink(videoForm.videoLink,'')">确认
            </el-button>
          </el-tab-pane>
          <el-tab-pane label="本地视频上传" name="second">
            <el-upload v-loading="loading" style="text-align: center;" drag :action="uploadVideoConfig.uploadUrl" accept="video/*" :name="uploadVideoConfig.name" :before-upload="onBeforeUploadVideo" :on-success="onSuccessVideo" :on-error="onErrorVideo" :multiple="false">
              <i class="el-icon-upload"></i>
              <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
              <div class="el-upload__tip" slot="tip">只能上传MP4文件,且不超过{{uploadVideoConfig.maxSize}}M</div>
            </el-upload>
          </el-tab-pane>
        </el-tabs>
      </el-dialog>
    </div>
  </div>
</template>
<script>
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor, Quill } from 'vue-quill-editor'
// 这里引入修改过的video模块并注册
import Video from './video'
Quill.register(Video, true)

// 设置title
import { setQuillTitle } from './quill-title.js'
// 工具栏
const toolbarOptions = [
  ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
  ["blockquote", "code-block"], // 引用  代码块
  [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
  [{ indent: "-1" }, { indent: "+1" }], // 缩进
  [{ size: ["small", false, "large", "huge"] }], // 字体大小
  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
  [{ align: [] }], // 对齐方式
  ["clean"], // 清除文本格式
  ['video'] // 视频
]
export default {
  name: 'RichTextEditor',
  components: {
    quillEditor
  },
  props: {
    /* 编辑器的内容 */
    content: { // 返回的html片段
      type: String,
      default: ''
    },
    // 视频上传配置
    uploadVideoConfig: {
      type: Object,
      default () {
        return {
          uploadUrl: '', // 上传地址
          maxSize: 10, // 图片上传大小限制,默认不超过2M
          name: 'Filedata' // 图片上传字段
        }
      }
    }
  },
  data () {
    let _self = this;
    return {
      loading: false, // 加载loading
      editorOptions: {
        placeholder: '',
        theme: 'snow', // or 'bubble'
        modules: {
          toolbar: {
            container: toolbarOptions, // 工具栏
            handlers: {
              'video': () => {
                // 覆盖默认的上传视频,点击视频图标,显示弹窗
                _self.videoForm.show = true
              }
            }
          }
        }
      },
      // 视频上传变量
      videoForm: {
        show: false, // 显示插入视频链接弹框的标识
        videoLink: '',
        activeName: 'first'
      }
    }
  },
  mounted () {
    // 初始给编辑器设置title
    setQuillTitle()
  },
  methods: {
    // 文本编辑
    onEditorChange ({ quill, html, text }) {
      console.log('editor changed:', quill, html, text)
      console.log('html.replace(/<[^>]*>|/g:', html.replace(/<[^>]*>|/g))
      this.$emit('update:content', html)
      this.$emit('change', html)
    },
    hideLoading () {
      this.loading = false
    },
    /** --------- 视频上传相关 start ---------  */
    insertVideoLink (videoLink, poster) {
      if (!videoLink) return this.$message.error('视频地址不能为空!')
      this.videoForm.show = false
      let quill = this.$refs['myQuillEditor'].quill
      // 获取富文本
      let range = quill.getSelection()
      // 获取光标位置:当编辑器中没有输入文本时,这里获取到的 range 为 null
      let index = range ? range.index : 0
      // 没有视频默认封面时,设置默认视频封面图片
      const img = poster ? poster : 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
      // 在光标所在位置 插入视频
      quill.insertEmbed(index, 'video', {
        url: videoLink,
        poster: img
      })
      // 调整光标到最后
      quill.setSelection(index + 1)
    },
    // el-文件上传组件
    onBeforeUploadVideo (file) {
      this.loading = true
      let acceptArr = ['video/mp4']
      const isVideo = acceptArr.includes(file.type)
      const isLt1M = file.size / 1024 / 1024 < this.uploadVideoConfig.maxSize
      if (!isVideo) {
        this.hideLoading()
        this.$message.error('只能上传mp4格式文件!')
      }
      if (!isLt1M) {
        this.hideLoading()
        this.$message.error(`上传文件大小不能超过 ${this.uploadVideoConfig.maxSize}MB!`)
      }
      return isLt1M && isVideo
    },
    // 文件上传成功时的钩子
    onSuccessVideo (res) {
      this.hideLoading()
      if (res.code === '100') {
        this.insertVideoLink(res.url, res.cover)
      } else {
        this.$message.error(res.desc)
      }
    },
    // 文件上传失败时的钩子
    onErrorVideo () {
      this.hideLoading()
      this.$message.error('上传失败')
    },
    /**--------- 视频上传相关 end --------- */
  }
}
</script>
<style  lang='less'>
.rich-text-editor-container .ql-container {
  height: 300px;
}

.rich-text-editor-container .ql-editor {
  padding: 0;
}

.rich-text-editor-container .ql-tooltip {
  left: 5px !important;
}
</style>

完整 quill-video.js 代码:

import { Quill } from "vue-quill-editor";
// 源码中是import直接倒入,这里要用Quill.import引入
const BlockEmbed = Quill.import('blots/block/embed')
const Link = Quill.import('formats/link')

const ATTRIBUTES = ['height', 'width']

class Video extends BlockEmbed {
  static create (value) {
    let node = super.create()
    // 添加video标签所需的属性
    node.setAttribute('controls', 'controls')
    node.setAttribute('playsinline', 'true')
    node.setAttribute('webkit-playsinline', 'true')
    node.setAttribute('type', 'video/mp4')
    // poster 属性指定视频下载时显示的图像,或者在用户点击播放按钮前显示的图像。
    node.setAttribute('poster', value.poster)
    node.setAttribute('src', this.sanitize(value.url))
    return node
  }

  static formats (domNode) {
    return ATTRIBUTES.reduce((formats, attribute) => {
      if (domNode.hasAttribute(attribute)) {
        formats[attribute] = domNode.getAttribute(attribute)
      }
      return formats
    }, {})
  }

  static sanitize (url) {
    return Link.sanitize(url) // eslint-disable-line import/no-named-as-default-member
  }

  static value (domNode) {
    // 设置自定义的属性值
    return {
      url: domNode.getAttribute('src'),
      poster: domNode.getAttribute('poster'),
    }
  }

  format (name, value) {
    if (ATTRIBUTES.indexOf(name) > -1) {
      if (value) {
        this.domNode.setAttribute(name, value)
      } else {
        this.domNode.removeAttribute(name)
      }
    } else {
      super.format(name, value)
    }
  }

  html () {
    const { video } = this.value()
    return `<a href="${video}">${video}</a>`
  }
}
Video.blotName = 'video' // 这里不用改,不用iframe,直接替换掉原来,如果需要也可以保留原来的,这里用个新的blot
Video.className = 'ql-video'  // 可添加样式,看实际使用需要
Video.tagName = 'video' // 用video标签替换iframe

export default Video
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue-quill-editor 富文本编辑器上传视频 的相关文章

随机推荐

  • C++ 大话设计之《访问者模式》(优缺点,设计原理,常用场景)

    访问者模式是一种行为型模式 优点 能够在不改变对象结构的情况下增加新的操作 使得操作集合可以相对独立地演化 缺点 增加新的元素类变得困难 因为每个新元素都必须被访问者类所接受 此外 如果对象结构中的元素类经常发生变化 那么使用访问者模式可能
  • 微信公众号订阅通知设置

    1 开通订阅通知 根据api开通 https developers weixin qq com doc offiaccount Subscription Messages intro html 2 设置订阅通知组件 根据api设置服务号订阅
  • linux dts 语法格式,设备树DTS格式解析

    8种机械键盘轴体对比 本人程序员 要买一个写代码的键盘 请问红轴和茶轴怎么选 宿主机 ubuntu16 04 开发板 tq imx6ull 内核版本 linux 4 1 15 用实例讲解下设备树dts语法 dts文档都在内核的arch ar
  • @antv/g2踩坑记录

    自定义tooltip 需要先在绘图时配置自定义tooltip的需要的字段 chart point position value 1 shape pointer tooltip name value date name value date
  • 投资合伙人股份分配_创业者必看的合伙人股权分配细则

    惠学习 创业者必看的合伙人股权分配细则 惠学习 创业者必看的合伙人股权分配细则 2016 08 03 苏州高新区惠创业 苏州高新区惠创业 案例 真功夫 真功夫的纠纷大家应该比较了解 现在对它的生意还不影响 但是很遗憾它还没IPO 最主要的原
  • Linux配置Java环境

    使用jdk压缩包方式配置Java环境 1 上传jdk到linux 在linux中软件一般安装到 usr local目录中 2 将jdk解压 解压命令 tar zxvf jdk 8u301 linux x64 tar gz 将解压后的jdk改
  • git子模块无法下载

    用rt studio添加软件包时会克隆整个仓库 这个时候如果提交代码 就会出现一个警告 如果你强行提交上去 那么这部分代码不会同步 但是你去远程仓库查看时会有一个子模块 如果你clone下来 想去下载子模块时 会提示 No url foun
  • 【Mybatis】maven配置pom.xml时找不到依赖项(已解决)

    我在配置pom xml依赖时 会冒红 解决方法 1 settings gt maven目录 把maven路径改为自己的 具体操作在 Maven Maven安装 入门教程笔记 暮色 年华的博客 CSDN博客 这篇文章里 2 右击pom xml
  • 独立成分分析FastICA算法原理

    独立成分分析FastICA算法原理 首先对于d维的随机变量 x R d 1
  • 【Android取证篇】华为设备跳出“允许USB调试“界面方法的不同方法

    Android取证篇 华为设备跳出 允许USB调试 界面方法的不同方法 华为设备在鸿蒙OS3系统之后 部分设备启用 允许USB调试 方式会有所变化 再次做个记录 蘇小沐 1 实验环境 系统 版本 Windows 11 专业工作站版 22H2
  • scons编译protobuffer脚本代码

    scons编译protobuffer脚本代码 protoc py Google s Protoc builder Example will produce c output files in the src directory protoc
  • Python选基金(爬虫+策略)

    之前买基金都瞎买的 最近突然想可以用python来试试 综合基金类型 持仓 收益率 基金经理多维度综合考虑 看看能不能帮忙选比较优质的基金出来 整体策略 一 数据准备 1 1获得基金经理信息 import requests import t
  • Qt 的 Qss使用

    Qt 的 Qss 是一种用于定义用户界面的样式表语言 它可以用来定义控件的颜色 字体 边框 背景等样式 可以很方便的实现自定义的样式效果 Qss 的基本语法和 CSS 类似 主要是由选择器和样式属性构成 选择器 选择器用来指定要样式化的控件
  • SIP协议&开源SIP服务器搭建和客户端安装

    1 SIP SIP 是一个应用层的控制协议 可以用来建立 修改 和终止多媒体会话 例如Internet电话 SIP在建立和维持终止多媒体会话协议上 支持五个方面 1 用户定位 检查终端用户的位置 用于通讯 2 用户有效性 检查用户参与会话的
  • 如何防止token伪造、篡改、窃取

    Token的伪造 窃取和篡改的安全问题 伪造 forgery 指攻击者伪造一个token 使系统错误地认为这是一个合法的token 从而获得未经授权的访问权限 窃取 theft 指攻击者通过某种手段获取到了一个合法的token 然后利用这个
  • RKE部署高可用Kubernetes集群

    RKE简介 RKE全称Rancher Kubernetes Engine 是一个快速的 多功能的 Kubernetes 安装工具 通过RKE 我们可以快速的安装一个高可用K8S集群 RKE 支持多种操作系统 包括 MacOS Linux 和
  • 抢滩登陆服务器维护,Intel CPU 一家独大市场结束?AMD 成功抢滩登陆-控制器/处理器-与非网...

    曾经 在服务器 CPU 市场 Intel 一家独大 但过去两年 AMD 凭借空前成功的 Zen 核心 以代号为 Naples 的 EPYC 霄龙 处理器强势杀入 从最大的云环境到 AI 应用领域 再到百亿级超级计算中心 AMD EYPC 均
  • el-table合并表头、动态合并列、合并尾部合计

    在有些情况下 我们会有合并表头 合并列 合并尾部合计的需求 这篇文章是为了记录 如何进行合并 方便日后翻阅 效果图 el table合并表头 el table合并列 动态合并 el table合并尾部合计 el table合并表头的实现 这
  • pytorch开源吗?

    pytorch开源吗 PyTorch的前身是Torch 其底层和Torch框架一样 但是使用Python重新写了很多内容 不仅更加灵活 支持动态图 而且提供了Python接口 它是由Torch7团队开发 是一个以Python优先的深度学习框
  • vue-quill-editor 富文本编辑器上传视频

    vue quill editor 富文本编辑器上传视频 插入视频 设置工具栏中文标题 修改视频 标签为