grapes.init.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. const panelsConfig = {
  2. stylePrefix: 'pn-', // 面板的样式前缀
  3. defaults: [
  4. {
  5. id: 'commands',
  6. buttons: [{}],
  7. },
  8. {
  9. id: 'options',
  10. buttons: [
  11. {
  12. active: false,
  13. id: 'sw-visibility',
  14. className: 'fa fa-square-o',
  15. command: 'core:component-outline',
  16. context: 'sw-visibility',
  17. attributes: { title: 'View components' },
  18. },
  19. {
  20. id: 'preview',
  21. className: 'fa fa-eye',
  22. command: 'preview',
  23. context: 'preview',
  24. attributes: { title: 'Preview' },
  25. },
  26. {
  27. id: 'fullscreen',
  28. className: 'fa fa-arrows-alt',
  29. command: 'fullscreen',
  30. context: 'fullscreen',
  31. attributes: { title: 'Fullscreen' },
  32. },
  33. // {
  34. // id: 'export-template',
  35. // className: 'fa fa-code',
  36. // command: 'export-template',
  37. // attributes: { title: 'View code' },
  38. // },
  39. ],
  40. },
  41. {
  42. id: 'views',
  43. buttons: [
  44. // {
  45. // id: 'open-sm',
  46. // className: 'fa fa-paint-brush',
  47. // command: 'open-sm',
  48. // active: false,
  49. // togglable: false,
  50. // attributes: { title: 'Open Style Manager' },
  51. // },
  52. {
  53. id: 'open-tm',
  54. className: 'fa fa-cog',
  55. command: 'open-tm',
  56. active: true,
  57. togglable: true,
  58. attributes: { title: 'Settings' },
  59. },
  60. // {
  61. // id: 'open-layers',
  62. // className: 'fa fa-bars',
  63. // command: 'open-layers',
  64. // togglable: false,
  65. // attributes: { title: 'Open Layer Manager' },
  66. // },
  67. // {
  68. // id: 'open-blocks',
  69. // className: 'fa fa-th-large',
  70. // command: 'open-blocks',
  71. // togglable: false,
  72. // attributes: { title: 'Open Blocks' },
  73. // },
  74. ],
  75. },
  76. ],
  77. };
  78. // 定义自定义组件类型
  79. const myNewComponentTypes = (editor) => {
  80. //连接属性
  81. // editor.Components.addType('a', {
  82. // isComponent: (el) => el.tagName === 'A',
  83. // model: {
  84. // defaults: {
  85. // traits: [
  86. // {
  87. // type: 'text', // Type of the trait
  88. // name: 'href', // (required) The name of the attribute/property to use on component
  89. // label: 'URL', // The label you will see in Settings
  90. // }
  91. // ],
  92. // },
  93. // },
  94. // });
  95. //图片属性
  96. editor.Components.addType('img', {
  97. isComponent: (el) => el.tagName === 'IMG',
  98. model: {
  99. defaults: {
  100. traits: [
  101. {
  102. type: 'text', // Type of the trait
  103. name: 'width', // (required) The name of the attribute/property to use on component
  104. label: 'width', // The label you will see in Settings
  105. },
  106. {
  107. type: 'text', // Type of the trait
  108. name: 'height', // (required) The name of the attribute/property to use on component
  109. label: 'height', // The label you will see in Settings
  110. },
  111. ],
  112. },
  113. },
  114. });
  115. };
  116. // 创建 GrapesJS 编辑器实例
  117. const editor = grapesjs.init({
  118. container: '#gjs', // 指定编辑器容器的 DOM 元素
  119. fromElement: true, // 从 DOM 元素中加载初始内容
  120. height: '100%', // 设置编辑器的高度
  121. width: '100%', // 设置宽度自适应
  122. storageManager: false,
  123. panels: panelsConfig,
  124. plugins: [myNewComponentTypes],
  125. canvas: {
  126. // 禁用对所有元素的选择
  127. selectorManager: {
  128. // 允许选择特定类名的元素
  129. selector: '.your-class-name',
  130. }
  131. }
  132. });
  133. const am = editor.AssetManager;
  134. // 锁定整个画布
  135. editor.getWrapper().set({ locked: true });
  136. // 遍历所有组件并解锁具有edit属性的组件
  137. const edit_classes = ['mtb_edit']; // 定义需要解锁的组件类名
  138. editor.getComponents().each(component => {
  139. component.onAll(component => {
  140. //解销CLASS
  141. let html = component.toHTML();
  142. const classes = component.getClasses();
  143. // 判断是否有交集
  144. const hasIntersection = classes.some(item => {
  145. // 如果是数组,则递归检查子数组
  146. if (Array.isArray(item)) {
  147. return item.some(subItem => edit_classes.includes(subItem));
  148. }
  149. // 如果是字符串,直接检查是否在 edit_classes 中
  150. return edit_classes.includes(item);
  151. });
  152. // 如果有交集,解锁组件
  153. if (hasIntersection || component.get('attributes').mtb_edit == 'true') {
  154. component.set({ locked: false });
  155. component.setStyle({
  156. border: '2px dashed #3b97e3 '
  157. });
  158. }
  159. })
  160. });
  161. // 监听组件选择事件
  162. editor.on('component:selected', (comp) => {
  163. //去掉选中组件后的按钮
  164. const selectedComponent = editor.getSelected();
  165. const defaultToolbar = selectedComponent.get('toolbar');
  166. selectedComponent.set({
  167. // toolbar: [ ...defaultToolbar, { attributes: {class: commandIcon}, command: commandToAdd}]
  168. toolbar: [ ]
  169. });
  170. //如果是连接与图片,显示右边的属性面板
  171. let tags = ['a', 'img'];
  172. const hasScheduleAttribute = selectedComponent.attributes;
  173. if (tags.includes(selectedComponent.attributes.tagName)) {
  174. editor.runCommand('open-tm');
  175. // 获取 .gjs-cv-canvas-bg 元素
  176. canvasBg = document.querySelector('.gjs-cv-canvas');
  177. canvasBg.classList.remove('gjs-cv-canvas-bg');
  178. var elements = document.querySelectorAll('.gjs-pn-views-container');
  179. elements.forEach(function(element) {
  180. element.style.display = 'block'; // 或者 'flex',取决于你希望如何显示这些元素
  181. });
  182. } else {
  183. canvasBg = document.querySelector('.gjs-cv-canvas');
  184. canvasBg.classList.add('gjs-cv-canvas-bg');
  185. var elements = document.querySelectorAll('.gjs-pn-views-container');
  186. elements.forEach(function(element) {
  187. element.style.display = 'none'; // 或者 'flex',取决于你希望如何显示这些元素
  188. });
  189. }
  190. // 双击图片时弹出图片管理器
  191. if (selectedComponent.attributes.tagName == 'img') {
  192. //双击图片时弹出图片管理器
  193. const el = selectedComponent.getEl();
  194. // 添加双击事件监听器
  195. el.addEventListener('dblclick', () => {
  196. am.open({
  197. types: ['image'], // This is the default option
  198. // Without select, nothing will happen on asset selection
  199. select(asset, complete) {
  200. const selected = editor.getSelected();
  201. if (selected) {
  202. selected.addAttributes({ src: asset.getSrc() });
  203. // The default AssetManager UI will trigger `select(asset, false)`
  204. // on asset click and `select(asset, true)` on double-click
  205. complete && am.close();
  206. }
  207. },
  208. });
  209. });
  210. }
  211. //其他
  212. });
  213. // 监听 load 事件
  214. editor.on('load', () => {
  215. // 在这里执行你的初始化逻辑
  216. // 获取目标元素
  217. const targetElement = document.querySelector('.fa-arrows-alt');
  218. // 创建下拉选择框
  219. const dropdown = document.createElement('select');
  220. dropdown.className = 'custom-select'; // 添加自定义样式类
  221. dropdown.id = 'dropdown'; // 添加 id 属性
  222. // 构建 option 标签
  223. var options = '';
  224. siteMenu.forEach(function (item) {
  225. if (mid == item.id) {
  226. options += `<option value="${item.id}" uri="${item.url}" selected>${item.title}</option>`;
  227. } else {
  228. options += `<option value="${item.id}" uri="${item.url}">${item.title}</option>`;
  229. }
  230. });
  231. // 将生成的 option 标签添加到 dropdown 中
  232. dropdown.innerHTML = options;
  233. // 将下拉选择框插入到目标元素之后
  234. targetElement.insertAdjacentElement('afterend', dropdown);
  235. //
  236. dropdownel = document.getElementById('dropdown');
  237. // 监听 change 事件
  238. dropdownel.addEventListener('change', function () {
  239. // 获取选中的 option
  240. var selectedOption = dropdownel.options[dropdownel.selectedIndex];
  241. // 获取选中的 id 和 uri
  242. var id = selectedOption.value;
  243. var uri = selectedOption.getAttribute('uri');
  244. if (id > 0) {
  245. // 生成跳转的 URL
  246. var redirectUrl = `?mid=${id}&uri=${encodeURIComponent(uri)}`;
  247. // 跳转到生成的 URL
  248. window.location.href = redirectUrl;
  249. }
  250. });
  251. });
  252. //更新时调用接口保存数据
  253. editor.on('update', () => {
  254. const html = editor.getHtml();
  255. // 你可以在这里添加自定义逻辑
  256. console.log('GrapesJS updated the editor content', html);
  257. });