Error in v-on handler: "TypeError: Cannot read property 'value' of undefined"
报错如下所示,即

在运行Vue项目时出现了上述错误,出现该错误的原因是其容器还未生成就对其进行了初始化所造成的。
首先检查有没有如下操作
1//原先取dom的操作 2document.getElementById('textarea'); 3//改正后,Vue中取demo的操作 4this.$refs.textarea
如果问题还没有解决,就是$refs依旧获取不到值,即取不到el-dialog对话框中的子组件对象,返回的都是undefined。在其外面加上如下所示,
1this.$nextTick(function () { 2 3});
比如我的this._initialize()方法里面获取不到 this.$refs.textarea的值,一直为undefined,我就在其外面加上了
1this.$nextTick(function () { 2 this._initialize(); 3});
如果问题还没有解决,你就要先打开el-dialog,让弹出框被初始化,只有el-dialog被初始化了,在Vue的渲染引擎中,你才可以获取到里面的子组件。
如下,我要做的是打开一个弹框,弹框里面是个form表单的table,table里面有个元素是在线编辑代码的,支持代码各语言的高亮显示。核心代码如下所示
1<template> 2 <div> 3 <!-- 操作按钮 --> 4 <el-button @click="handleAdd">新增</el-button> 5 6 <!-- 对话框内容 --> 7 <el-dialog :title="title" :visible.sync="open" width="1000px"> 8 <el-form ref="form" :model="form" label-width="80px"> 9 <el-form-item label="脚本内容"> 10 <div class="in-coder-panel"> 11 <textarea ref="textarea"></textarea> 12 <el-select class="code-mode-select" v-model="mode" @change="changeMode"> 13 <el-option v-for="mode in modes" :key="mode.value" :label="mode.label" :value="mode.value"> 14 </el-option> 15 </el-select> 16 </div> 17 </el-form-item> 18 </el-form> 19 </el-dialog> 20 21 </div> 22</template> 23 24<script> 25 // 引入全局实例 26 import CodeMirror from 'codemirror' 27 // 核心样式 28 import 'codemirror/lib/codemirror.css' 29 // 引入主题后还需要在 options 中指定主题才会生效 30 import 'codemirror/theme/idea.css' 31 32 // 需要引入具体的语法高亮库才会有对应的语法高亮效果 33 // codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库 34 // 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入 35 import 'codemirror/mode/javascript/javascript.js' 36 import 'codemirror/mode/css/css.js' 37 import 'codemirror/mode/xml/xml.js' 38 import 'codemirror/mode/shell/shell.js' 39 import 'codemirror/mode/sql/sql.js' 40 41 //代码补全提示 42 import 'codemirror/addon/hint/anyword-hint.js'; 43 import 'codemirror/addon/hint/css-hint.js'; 44 import 'codemirror/addon/hint/html-hint.js'; 45 import 'codemirror/addon/hint/javascript-hint.js'; 46 import 'codemirror/addon/hint/show-hint.css'; 47 import 'codemirror/addon/hint/show-hint.js'; 48 import 'codemirror/addon/hint/sql-hint.js'; 49 import 'codemirror/addon/hint/xml-hint.js'; 50 51 export default { 52 name: "Code", 53 54 props: { 55 // 外部传入的内容,用于实现双向绑定 56 value: String, 57 // 外部传入的语法类型 58 language: { 59 type: String, 60 default: null 61 } 62 }, 63 64 data() { 65 return { 66 // 内部真实的内容 67 code: '#!/bin/bash\n' + 68 'cd /root/\n' + 69 'list=(`ls`)\n' + 70 ' \n' + 71 'for i in ${list[@]}\n' + 72 'do\n' + 73 ' if [ -d $i ]\n' + 74 ' then\n' + 75 ' cp -r $i /tmp/\n' + 76 ' fi\n' + 77 'done', 78 // 默认的语法类型 79 mode: 'shell', 80 // 编辑器实例 81 coder: null, 82 // 默认配置 83 options: { 84 // 缩进格式 85 tabSize: 4, 86 // 主题,对应主题库 JS 需要提前引入 87 theme: 'idea', 88 // 显示行号 89 lineNumbers: true, 90 line: true, 91 extraKeys: {"Ctrl": "autocomplete"}, 92 }, 93 // 支持切换的语法高亮类型,对应 JS 已经提前引入 94 // 使用的是 MIME-TYPE ,不过作为前缀的 text/ 在后面指定时写死了 95 modes: [{ 96 value: 'css', 97 label: 'CSS' 98 }, { 99 value: 'javascript', 100 label: 'Javascript' 101 }, { 102 value: 'html', 103 label: 'XML/HTML' 104 }, { 105 value: 'x-sh', 106 label: 'Shell' 107 }, { 108 value: 'x-sql', 109 label: 'SQL' 110 }], 111 // 弹出层标题 112 title: "", 113 // 是否显示弹出层 114 open: false, 115 }, 116 117 methods: { 118 // 初始化 119 _initialize() { 120 // 初始化编辑器实例,传入需要被实例化的文本域对象和默认配置 121 this.coder = CodeMirror.fromTextArea(this.$refs.textarea, this.options) 122 // 编辑器赋值 123 this.coder.setValue(this.value || this.code) 124 125 // 支持双向绑定 126 this.coder.on('change', (coder) => { 127 this.code = coder.getValue() 128 129 if (this.$emit) { 130 this.$emit('input', this.code) 131 } 132 }) 133 134 // 尝试从父容器获取语法类型 135 if (this.language) { 136 // 获取具体的语法类型对象 137 let modeObj = this._getLanguage(this.language) 138 139 // 判断父容器传入的语法是否被支持 140 if (modeObj) { 141 this.mode = modeObj.label 142 } 143 } 144 }, 145 // 获取当前语法类型 146 _getLanguage(language) { 147 // 在支持的语法类型列表中寻找传入的语法类型 148 return this.modes.find((mode) => { 149 // 所有的值都忽略大小写,方便比较 150 let currentLanguage = language.toLowerCase() 151 let currentLabel = mode.label.toLowerCase() 152 let currentValue = mode.value.toLowerCase() 153 154 // 由于真实值可能不规范,例如 java 的真实值是 x-java ,所以讲 value 和 label 同时和传入语法进行比较 155 return currentLabel === currentLanguage || currentValue === currentLanguage 156 }) 157 }, 158 // 更改模式 159 changeMode(val) { 160 // 修改编辑器的语法配置 161 this.coder.setOption('mode', `text/${val}`) 162 163 // 获取修改后的语法 164 let label = this._getLanguage(val).label.toLowerCase() 165 166 // 允许父容器通过以下函数监听当前的语法值 167 this.$emit('language-change', label) 168 }, 169 170 /** 按钮操作 */ 171 handleAdd() { 172 this.open = true; 173 this.title = "新增脚本"; 174 this.$nextTick(function () { 175 this._initialize(); 176 }); 177 }, 178 } 179 }; 180</script> 181 182<style lang="stylus" rel="stylesheet/stylus"> 183 .in-coder-panel 184 flex-grow 1 185 display flex 186 position relative 187 188 .CodeMirror 189 flex-grow 1 190 z-index 1 191 .CodeMirror-code 192 line-height 19px 193 194 .code-mode-select 195 position absolute 196 z-index 2 197 right 10px 198 top 10px 199 max-width 130px 200</style>
最终效果图如下
