ueditor.vue 6.2 KB

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