首页 > 其他分享 >vue 编辑器+使用场景+问题解决

vue 编辑器+使用场景+问题解决

时间:2023-12-03 20:56:24浏览次数:33  
标签:nextTick vue JSON 编辑器 场景 import codemirror 弹窗 editingData

vue 编辑器组件

  • 添加依赖

    "dependencies": {
        "@codemirror/autocomplete": "^6.4.2",
        "@codemirror/commands": "^6.2.1",
        "@codemirror/lang-javascript": "^6.0.2",
        "@codemirror/lang-sql": "^6.0.0",
        "@codemirror/language": "^6.6.0",
        "@codemirror/lint": "^6.2.0",
        "@codemirror/search": "^6.2.3",
        "@codemirror/state": "^6.2.0",
        "@codemirror/view": "^6.11.2",
        "codemirror": "^5.65.15"
    },
    
  • 导入组件:

    const scCodeEditor = defineAsyncComponent(() => import("../codeEdit.vue"))
    
    export default {
      components: {
        scCodeEditor
      },
    // ......
    
  • 使用标签:<sc-code-editor></sc-code-editor>

使用场景

<el-dialog v-model="showDatasetDialog" title="数据编辑">
    <sc-code-editor v-model="editingData" :height="400"></sc-code-editor>
    <div style="display: flex; justify-content: center; align-items: center;">
        <span style="margin: auto">
            <el-button type="primary" @click="saveDataset" size="default">确认</el-button>
            <el-button @click="cancelDatasetEdit" size="default">取消</el-button>
        </span>
    </div>
</el-dialog>
  • 是在下拉的标签 <el-collapse-item>v-for 循环显示多条数据中,内含一个触发弹窗的按钮:

    <el-form-item label="y轴数据:">
        <el-button @click="editDataset(seriesItem)" size="default">编辑</el-button>
    </el-form-item>
    
  • 编辑按钮

    // 编辑数据
    editDataset(seriesItem) {
      this.showDatasetDialog = true; // 打开弹窗
      nextTick(() => {
        this.editingData = JSON.stringify(seriesItem.data);
        this.newSeriesItem = seriesItem
      })
    },
    
  • 保存按钮

    // 保存的确定按钮
    saveDataset() {
      this.newSeriesItem.data = JSON.parse(this.editingData);
      this.showDatasetDialog = false;
      this.editingData = '';
    },
    
    
  • 取消按钮

    // 取消按钮
    cancelDatasetEdit() {
      this.editingData = '';
      this.showDatasetDialog = false;
    },
    

出现问题并解决

  1. 传到编辑器中的文本不对,不是想要的样式

    • 看编辑器组件内 props 接收的是什么类型,JSON.stringify 返回的是 JSON 字符串,而 JSON.parse 返回的是一个对象,要在合适的地方恰当转换
    • this.editingData 在定义时置空不是 null,而应该是 “ ”
  2. 编辑器弹窗点击右上角的叉号关闭不是立刻关,更像是点一下叉号连着关了多个弹窗

    • 这个问题可能与 v-model 绑定和 v-for 循环结合使用时的共享状态有关,一个方法是尝试为每个弹窗使用不同的状态,而不是在循环中共享相同的 showDatasetDialog
    • 另一个简单的方式也有效,就是尽量把弹窗拿出来放到外层,不要放循环里
  3. 没加 nextTick() 的时候,打开编辑器后没有数据,点击一下弹窗内部获取焦点后才会显示数据:

    editDataset(seriesItem) {
      this.showDatasetDialog = true;
      this.editingData = JSON.stringify(seriesItem.data);
      this.newSeriesItem = seriesItem
    },
    
    • 这个问题可能是由于在 editDataset() 方法中,弹窗被打开的时候,editingData 可能还没有被正确地设置,导致初始时是空白的(在 Vue 中,数据更新是异步的,因此在 editDataset 中设置 this.editingData 后,如果直接打开弹窗,可能会在弹窗中渲染时发现数据还没有更新),解决方案就是最开始展示的加上 nextTick()
    • 使用 nextTick 的目的是等待当前数据更新完成后再执行代码块(可以理解为执行完 nextTick 里的语句后才会执行此方法里 nextTick 之外的语句),确保了 editingData 已经包含了正确的数据,然后再打开弹窗,就不再出现空白的问题了

第三方编辑器组件

  • codeEdit.vue:

    <template>
        <div class="sc-code-editor" :style="{ 'height': _height }" style="z-index: 10000">
            <textarea ref="textarea" v-model="contentValue"></textarea>
        </div>
    </template>
    
    <script>
    import { markRaw } from "vue";
    
    //框架
    import CodeMirror from "codemirror";
    import "codemirror/lib/codemirror.css";
    
    //主题
    import "codemirror/theme/idea.css";
    import "codemirror/theme/darcula.css";
    
    //功能
    import "codemirror/addon/selection/active-line";
    
    //语言
    import "codemirror/mode/javascript/javascript";
    import "codemirror/mode/sql/sql";
    
    export default {
        props: {
            modelValue: {
                type: String,
                default: ""
            },
            mode: {
                type: String,
                default: "javascript"
            },
            height: {
                type: [String, Number],
                default: 300
            },
            options: {
                type: Object,
                default: () => {}
            },
            theme: {
                type: String,
                default: "idea"
            },
            readOnly: {
                type: Boolean,
                default: false
            }
        },
        data() {
            return {
                contentValue: this.modelValue,
                coder: null,
                opt: {
                    theme: this.theme, //主题
                    styleActiveLine: true, //高亮当前行
                    lineNumbers: true, //行号
                    lineWrapping: false, //自动换行
                    tabSize: 4, //Tab缩进
                    indentUnit: 4, //缩进单位
                    indentWithTabs: true, //自动缩进
                    mode: this.mode, //语言
                    readOnly: this.readOnly, //只读
                    autoFormatOnLoad: true,
                    ...this.options
                }
            };
        },
        computed: {
            _height() {
                return Number(this.height) ? Number(this.height) + "px" : this.height;
            }
        },
        watch: {
            modelValue(val) {
                this.contentValue = val;
                if (val !== this.coder.getValue()) {
                    this.coder.setValue(val);
                }
            }
        },
        mounted() {
            this.$nextTick(() => {
                this.init();
            });
    
            //获取挂载的所有modes
            //console.log(CodeMirror.modes)
        },
        methods: {
            init() {
                this.coder = markRaw(CodeMirror.fromTextArea(this.$refs.textarea, this.opt));
                this.coder.on("change", coder => {
                    this.contentValue = coder.getValue();
                    this.$emit("update:modelValue", this.contentValue);
                });
            },
            formatStrInJson(strValue) {
                return JSON.stringify(JSON.parse(strValue), null, 4);
            }
        }
    };
    </script>
    
    <style scoped>
    .sc-code-editor {
        font-size: 14px;
        border: 1px solid #ddd;
        line-height: 150%;
    }
    .sc-code-editor:deep(.CodeMirror) {
        height: 100%;
    }
    </style>
    
  • 小提一嘴:在 Vue 中,数据更新是异步的,即当你修改了 Vue 实例的数据时,Vue 并不会立即应用这个变化,而是将变化放入一个队列中,然后在一个事件循环周期内异步地执行这些变化,最终更新视图。这种机制可以提高性能,避免不必要的重复渲染。

    • 在这种情况下,如果你在更新数据后立即访问这个数据,可能会得到之前的旧值,因为实际的数据更新是异步执行的。所以,上述如果在数据更新后立即打开弹窗,可能会在弹窗中渲染时发现数据还没有被正确地更新。
    • 所以通过使用 nextTick,你确保在其内部的回调(在其中更新 this.editingDatathis.newSeriesItem)将在下一个 DOM 更新周期之后执行。这确保了当你访问和设置 this.editingData 时,DOM 已经以最新的数据更新,防止在对话框中看到空白数据的问题。

标签:nextTick,vue,JSON,编辑器,场景,import,codemirror,弹窗,editingData
From: https://www.cnblogs.com/zhu-ya-zhu/p/17873742.html

相关文章

  • vue 循环显示数据场景
    vue循环显示数据el-table中<template> <el-table:data="goodsList"> <el-table-columnprop="goodsName"label="商品名称"></el-table-column> <!--......--></el-table></template>......
  • 基于uQRCode封装的Vue3二维码生成插件
    标题:基于uQRCode封装的Vue3二维码生成插件摘要:本文介绍了一种基于uQRCode封装的Vue3二维码生成插件,可以在Javascript运行环境下生成二维码并返回图片地址。该插件适用于所有Javascript运行环境,并且支持微信小程序。本文将详细介绍该插件的使用方法,并给出一个基于Vue3的示例。关......
  • 自定义精美商品分类列表组件 侧边栏商品分类组件 category组件(适配vue3)
    随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身。通过组件化开发,可以有效实现单独开发,单独维护,而且他们之间可以随意的进行组合。大大提升开发效率......
  • vue3中css使用js中的变量
    <scriptsetuplang="ts">import{SoundOutlined}from'@ant-design/icons-vue'constprops=defineProps({title:{type:String,default:''},color:{type:String,default:'#000'}......
  • Vue 常用的指令都有哪些?
    1、v-model多用于表单元素实现双向数据绑定(同angular中的ng-model)2、v-for格式:v-for="字段名in(of)数组json"循环数组或json(同angular中的ng-repeat),需要注意从vue2开始取消了$index3、v-show显示内容(同angular中的ng-show)4、v-hide隐藏内容(同angular......
  • Vue3 读取Hdr 文件转Image显示
    import{decodeRGBE}from'@derschmale/io-rgbe';//引入io-rgbe//读取Hdr文件constReadHdrFile=(buffer:ArrayBufferLike&{BYTES_PER_ELEMENT?:undefined;})=>{consthdri=decodeRGBE(newDataView(buffer))constdata=hdri.data;......
  • VUE四个生命阶段和8个钩子函数的执行及其实现效果------VUE框架
    VUE四个生命阶段和8个钩子函数的执行及其实现效果<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>D......
  • 图数据库Neo4j概念、应用场景、安装及CQL的使用
    一、图数据库概念引用SethGodin的说法,企业需要摒弃仅仅收集数据点的做法,开始着手建立数据之间的关联关系。数据点之间的关系甚至比单个点本身更为重要。传统的**关系数据库管理系统(RDBMS)**并不擅长处理数据之间的关系,那些表状数据模式和呆板的结构难以添加新连接或不同类型连接......
  • 多媒体应用设计师 第17章 多媒体应用场景的技术应用和实现示例
    口诀【虚入手跟交立眼】(虚拟现实系统的输入设备:数据手套、三维位置跟踪器、三维空间交互球、立体眼镜)**【虚出视听触】【视头洞响墙】【听耳喇】【触触力】**虚拟现实系统的输出设备:视觉感知设备(头盔式显示器、洞穴式立体显示装置、响应工作台显示装置、墙式投影......
  • 5G城市微蜂窝场景的信道测量与建模
    https://www.mdpi.com/1424-8220/16/8/1330https://www.mdpi.com/1424-8220/16/8/1330https://www.mdpi.com/1424-8220/16/8/13305G城市微蜂窝场景的信道测量与建模作者:MichaelPeter、RichardJ.Weiler、BarışGöktepe、WilhelmKeusgen和KeiSakaguchi传感器2016,16(8),1330;https......