需求背景是有个功能需要维护YAML文本格式的配置,实现思路是通过codemirror实现文本编辑器,通过js-yaml做类型转换和格式校验的工作。
首先请自行安装两个依赖库:npm install js-yaml codemirror,安装完以后,直接上vue代码,运行访问该vue的页面即可看到效果
<template><divclass="app-container"><el-card><divclass="json-editor"><textarearef="textarea"/></div><divstyle="text-align: left;margin-top:5px;"><el-buttontype="primary"@click="confirm">创建</el-button><el-buttontype="danger"@click="cancelButton">取消</el-button></div></el-card></div></template><script>importCodeMirrorfrom"codemirror"; import"codemirror/addon/lint/lint.css"; import"codemirror/lib/codemirror.css"; import"codemirror/theme/rubyblue.css"; import"codemirror/mode/yaml/yaml"; import"codemirror/addon/lint/lint"; import"codemirror/addon/lint/yaml-lint"; importYAMLfrom'js-yaml'; window.jsyaml=require("js-yaml"); exportdefault { name: "ConfigYaml", props: [], components: {}, data() { return { value:'', validationErrors:[], yamlEditor: false }; }, mounted(){ // CodeMirror的配置项,搜官网看这里的配置项配置this.yamlEditor=CodeMirror.fromTextArea(this.$refs.textarea, { lineNumbers: true, // 是否显示行数mode: "text/x-yaml", // 接受的类型,json xml....gutters: ["CodeMirror-lint-markers"], // 样式的宽度theme: "rubyblue", // 主题lint: true }); this.value=`apiVersion: v1kind: Podmetadata:namespace: namespace1name:`; this.yamlEditor.setValue(this.value); this.yamlEditor.on("change", cm=> { // this.$emit("changed", cm.getValue());// 编辑json框里面的内容可以时刻监听到值,通过cm.getValue()获取到 }); }, created() { }, activated() { }, methods: { confirm(){ console.log(this.yamlEditor.getValue()) this.validateYaml(this.yamlEditor.getValue()); if (this.validationErrors.length==0) { console.log('YAML格式有效'); } else { console.log('YAML格式无效'); console.log(this.validationErrors); } }, validateYaml(yamlData) { try { letdata=YAML.load(yamlData); this.validationErrors=this.validateFields(data); } catch (error) { console.error(error); this.validationErrors= ['Invalid YAML format']; } }, validateFields(yamlData) { constrequiredFields= ['metadata.name']; // 替换为所需的字段名consterrors= []; console.log(yamlData) for (constfieldofrequiredFields) { if (!this.hasProperty(yamlData,field)) { errors.push(`Missing field: ${field}`); } elseif (!this.getValueByPath(yamlData,field)) { errors.push(`Empty value for field: ${field}`); } } returnerrors; }, getValueByPath(obj, path) { constproperties=path.split('.'); letvalue=obj; for (constpropertyofproperties) { if (value.hasOwnProperty(property)) { value=value[property]; } else { returnundefined; } } returnvalue; }, hasProperty(obj, propertyPath) { constproperties=propertyPath.split('.'); letcurrentObj=obj; for (constpropertyofproperties) { if (!currentObj.hasOwnProperty(property)) { returnfalse; } currentObj=currentObj[property]; } returntrue; }, cancelButton(){ this.$store.dispatch("tagsView/delView", this.$route).then(() => { this.$router.push({ name: "xxx" }); }); }, } }; </script><stylescoped>.json-editor { height: 500px; position: relative; } .json-editor >>> .CodeMirror { height: 500px; min-height: 300px; } .json-editor >>> .CodeMirror-scroll { min-height: 300px; } .json-editor >>> .cm-s-rubybluespan.cm-string { color: #f08047; } </style><stylelang="less"scoped>.floatdiv{ float: left; } .timeUintDiv{ line-height: 30px; margin-left: 5%; } ::v-deep.divInSelect.el-input__inner { border: none; box-shadow: none; } </style>
cancelButton是关闭操作,暂时不用关心,各自根据各自的需求做调整,主要是初始化this.value到yamlEditor文本编辑器中,该编辑器由于js-yaml的加持,就带有了YAML文本格式是否规范的校验,然后点击创建的时候,会去判断是否包含业务层需要的属性,比如 const requiredFields = ['metadata.name']; // 替换为所需的字段名 这段描述,可以改为自己的必填字段,这个地方可以从数据库读,放置在该地方欠妥当,可以放到data里。紧接着就是判断是否含有该字段,以及该字段有没有值,主要是两个函数hasProperty和getValueByPath,支持循环深入判断,运行结果如下几张图:
上述测试情况分别对应的是成功,格式有误,metadata.name字段不存在,metadata.name字段的值为空。可以根据业务进一步扩展校验规则,以及提示的方式。