1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
| <template> <div> <script :id="id" :name="name" type="text/plain"></script> </div> </template>
<script> import config from './ueditor.config' // 一个简单的事件订阅发布的实现,取代原始Event对象,提升IE下的兼容性 class LoadEvent { constructor () { this.listeners = {} } on (eventName, callback) { this.listeners[eventName] === undefined ? (this.listeners[eventName] = []) : '' this.listeners[eventName].push(callback) } emit (eventName) { this.listeners[eventName] && this.listeners[eventName].forEach(callback => callback()) } } export default { name: 'VueNeditorWrap', data () { return { id: 'editor' + Math.random() .toString() .slice(-10), editor: null, isReady: false, // 实例是否已经ready readyValue: '', // ready之后给编辑器设置的值 defaultConfig: { UEDITOR_HOME_URL: './public/NEditor/', enableAutoSave: false } } }, props: { value: { type: String, default: '' }, config: { type: Object, default: function () { return {} } }, init: { type: Function, default: function () { return () => {} } }, destroy: Boolean, name: String }, computed: { mixedConfig () { return Object.assign({}, this.defaultConfig, config) } }, methods: { // 添加自定义按钮 registerButton: ({ name, icon, tip, handler, UE = window.UE }) => { UE.registerUI(name, (editor, name) => { editor.registerCommand(name, { execCommand: () => { handler(editor, name) } }) const btn = new UE.ui.Button({ name, title: tip, cssRules: `background-image: url(${icon}) !important;background-size: cover;`, onclick () { editor.execCommand(name) } }) editor.addListener('selectionchange', () => { const state = editor.queryCommandState(name) if (state === -1) { btn.setDisabled(true) btn.setChecked(false) } else { btn.setDisabled(false) btn.setChecked(state) } }) return btn }) }, // 实例化编辑器之前-JS依赖检测 _beforeInitEditor (value) { // console.log('_beforeInitEditor', value + '--') // 准确判断ueditor.config.js和ueditor.all.js是否均已加载 仅加载完ueditor.config.js时UE对象和UEDITOR_CONFIG对象也存在,仅加载完ueditor.all.js时UEDITOR_CONFIG对象也存在,但为空对象 !!window.UE && !!window.UEDITOR_CONFIG && Object.keys(window.UEDITOR_CONFIG).length !== 0 && !!window.UE.getEditor ? this._initEditor(value) : this._loadScripts().then(() => this._initEditor(value)) }, // 实例化编辑器 _initEditor (value) { this.$nextTick(() => { this.init() this.editor = window.UE.getEditor(this.id, this.mixedConfig) this.readyValue = value this.editor.addListener('ready', () => { this.isReady = true this.$emit('ready', this.editor) this.editor.setContent(this.readyValue) this.editor.addListener('contentChange', () => { // console.log('input', this.editor.getContent()) this.$emit('input', this.editor.getContent()) }) }) }) }, // 动态添加JS依赖 _loadScripts () { // 确保多个实例同时渲染时不会重复创建SCRIPT标签 if (window.loadEnv) { return new Promise((resolve, reject) => { window.loadEnv.on('scriptsLoaded', function () { resolve() }) }) } else { window.loadEnv = new LoadEvent() return new Promise((resolve, reject) => { // 如果在其他地方只引用ueditor.all.min.js,在加载ueditor.config.js之后仍需要重新加载ueditor.all.min.js,所以必须确保ueditor.config.js已加载 // this._loadService().then(() => this._loadConfig()).then(() => this._loadCore()).then(() => { // window.loadEnv.emit("scriptsLoaded"); // resolve(); // }); const that = this that._loadParse().then(() => that._loadConfig()).then(() => that._loadCore()).then(() => that._loadService()).then(() => { window.loadEnv.emit('scriptsLoaded') resolve() }).catch(err => { console.error(err) }) }) } }, _loadConfig () { return new Promise((resolve, reject) => { if ( !!window.UE && !!window.UEDITOR_CONFIG && Object.keys(window.UEDITOR_CONFIG).length !== 0 ) { resolve() } }) }, _loadService () { return new Promise((resolve, reject) => { let coreScript = document.createElement('script') coreScript.type = 'text/javascript' coreScript.src = this.mixedConfig.UEDITOR_HOME_URL + 'neditor.service.js' document.getElementsByTagName('head')[0].appendChild(coreScript) coreScript.onload = function () { resolve() } }) }, _loadParse () { return new Promise((resolve, reject) => { let coreScript = document.createElement('script') coreScript.type = 'text/javascript' coreScript.src = this.mixedConfig.UEDITOR_HOME_URL + 'neditor.parse.min.js' document.getElementsByTagName('head')[0].appendChild(coreScript) coreScript.onload = function () { resolve() } }) }, _loadCore () { return new Promise((resolve, reject) => { resolve() }) }, // 设置内容 _setContent (value) { if (this.isReady) { // console.log('setContentisReady', value) value === this.editor.getContent() || this.editor.setContent(value) } else { // console.log('noisReady', value) this.readyValue = value } } }, beforeDestroy () { if (this.destroy && this.editor && this.editor.destroy) { this.editor.destroy() } }, // v-model语法糖实现 watch: { value: { handler (value) { // console.log('vvv===', value) this.editor ? this._setContent(value) : this._beforeInitEditor(value) }, immediate: true } } } </script>
|