const panelsConfig = { stylePrefix: 'pn-', // 面板的样式前缀 defaults: [ { id: 'commands', buttons: [{}], }, { id: 'options', buttons: [ { active: false, id: 'sw-visibility', className: 'fa fa-square-o', command: 'core:component-outline', context: 'sw-visibility', attributes: { title: 'View components' }, }, { id: 'preview', className: 'fa fa-eye', command: 'preview', context: 'preview', attributes: { title: 'Preview' }, }, { id: 'fullscreen', className: 'fa fa-arrows-alt', command: 'fullscreen', context: 'fullscreen', attributes: { title: 'Fullscreen' }, }, // { // id: 'export-template', // className: 'fa fa-code', // command: 'export-template', // attributes: { title: 'View code' }, // }, ], }, { id: 'views', buttons: [ // { // id: 'open-sm', // className: 'fa fa-paint-brush', // command: 'open-sm', // active: false, // togglable: false, // attributes: { title: 'Open Style Manager' }, // }, { id: 'open-tm', className: 'fa fa-cog', command: 'open-tm', active: true, togglable: true, attributes: { title: 'Settings' }, }, // { // id: 'open-layers', // className: 'fa fa-bars', // command: 'open-layers', // togglable: false, // attributes: { title: 'Open Layer Manager' }, // }, // { // id: 'open-blocks', // className: 'fa fa-th-large', // command: 'open-blocks', // togglable: false, // attributes: { title: 'Open Blocks' }, // }, ], }, ], }; // 定义自定义组件类型 const myNewComponentTypes = (editor) => { //连接属性 // editor.Components.addType('a', { // isComponent: (el) => el.tagName === 'A', // model: { // defaults: { // traits: [ // { // type: 'text', // Type of the trait // name: 'href', // (required) The name of the attribute/property to use on component // label: 'URL', // The label you will see in Settings // } // ], // }, // }, // }); //图片属性 editor.Components.addType('img', { isComponent: (el) => el.tagName === 'IMG', model: { defaults: { traits: [ { type: 'text', // Type of the trait name: 'title', // (required) The name of the attribute/property to use on component label: 'title', // The label you will see in Settings }, { type: 'text', // Type of the trait name: 'width', // (required) The name of the attribute/property to use on component label: 'width', // The label you will see in Settings }, { type: 'text', // Type of the trait name: 'height', // (required) The name of the attribute/property to use on component label: 'height', // The label you will see in Settings }, ], }, }, }); }; const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); // 创建 GrapesJS 编辑器实例 const editor = grapesjs.init({ container: '#gjs', // 指定编辑器容器的 DOM 元素 fromElement: true, // 从 DOM 元素中加载初始内容 height: '100%', // 设置编辑器的高度 width: '100%', // 设置宽度自适应 storageManager: false, panels: panelsConfig, plugins: [myNewComponentTypes], assetManager: { upload: '/dist/visual-editor/upload', uploadName: '_file_', multiUpload:false, headers: { 'X-CSRF-TOKEN': csrfToken, }, }, }); const am = editor.AssetManager; // 锁定整个画布 editor.getWrapper().set({ locked: true }); // 遍历所有组件并解锁具有edit属性的组件 const edit_classes = ['mtb_edit']; // 定义需要解锁的组件类名 editor.getComponents().each(component => { component.onAll(component => { //解销CLASS let html = component.toHTML(); const classes = component.getClasses(); // 判断是否有交集 const hasIntersection = classes.some(item => { // 如果是数组,则递归检查子数组 if (Array.isArray(item)) { return item.some(subItem => edit_classes.includes(subItem)); } // 如果是字符串,直接检查是否在 edit_classes 中 return edit_classes.includes(item); }); // 如果有交集,解锁组件 if (hasIntersection || component.get('attributes').mtb_edit == 'true') { component.set({ locked: false }); setBorder(component); } if (component.get('attributes').mtb_edit == 'false') { component.set({ locked: true }); } if (component.get('attributes').mtb_edit_this == 'true') { component.set({ locked: false }); setBorder(component); //关闭子组件 component.forEachChild(child => { child.set({ locked: true }); }) } if (component.get('attributes').mtb_edit_this == 'false') { component.set({ locked: true }); } }) }); function setBorder(component) { if (component.attributes.tagName == 'a') { component.setStyle({ border: '3px dashed #f08300' }); } else { component.setStyle({ border: '1px dashed #3b97e3' }); } } // 监听组件选择事件 editor.on('component:selected', (comp) => { //去掉选中组件后的按钮 const selectedComponent = editor.getSelected(); const defaultToolbar = selectedComponent.get('toolbar'); selectedComponent.set({ // toolbar: [ ...defaultToolbar, { attributes: {class: commandIcon}, command: commandToAdd}] toolbar: [ ] }); //如果是连接与图片,显示右边的属性面板 // let tags = ['a', 'img']; // const hasScheduleAttribute = selectedComponent.attributes; // if (tags.includes(selectedComponent.attributes.tagName)) { // //editor.runCommand('open-tm'); // } else { // } // 双击图片时弹出图片管理器 if (selectedComponent.attributes.tagName == 'img') { //双击图片时弹出图片管理器 const el = selectedComponent.getEl(); // 添加双击事件监听器 el.addEventListener('dblclick', () => { am.open({ types: ['image'], // This is the default option // Without select, nothing will happen on asset selection select(asset, complete) { const selected = editor.getSelected(); if (selected) { selected.addAttributes({ src: asset.getSrc() }); // The default AssetManager UI will trigger `select(asset, false)` // on asset click and `select(asset, true)` on double-click complete && am.close(); } }, }); }); } //其他 }); var open_tm_show = true; var cogIcons = document.querySelectorAll('.fa-cog'); cogIcons.forEach(function(icon) { icon.addEventListener('click', function() { // 在这里执行你想要的操作 if (open_tm_show) { open_tm_show = false; } else { open_tm_show = true; } leftPanelDisplay(open_tm_show); }); }); function leftPanelDisplay(isShow = true) { if (isShow) { // canvasBg = document.querySelector('.gjs-cv-canvas'); // canvasBg.classList.remove('gjs-cv-canvas-bg'); let elements1 = document.querySelectorAll('.gjs-pn-views-container'); elements1.forEach(function(element) { element.style.display = 'block'; // 或者 'flex',取决于你希望如何显示这些元素 }); let elements2 = document.querySelectorAll('.gjs-pn-views'); elements2.forEach(function(element) { element.style = 'border_bottom: 2px solid var(--gjs-main-dark-color)'; }); } else { // canvasBg = document.querySelector('.gjs-cv-canvas'); // canvasBg.classList.add('gjs-cv-canvas-bg'); let elements1 = document.querySelectorAll('.gjs-pn-views-container'); elements1.forEach(function(element) { element.style.display = 'none'; // 或者 'flex',取决于你希望如何显示这些元素 }); let elements2 = document.querySelectorAll('.gjs-pn-views'); elements2.forEach(function(element) { element.style = 'border:none'; }); } } // 监听 load 事件 editor.on('load', () => { // 在这里执行你的初始化逻辑 // 获取目标元素 const targetElement = document.querySelector('.fa-arrows-alt'); // 创建下拉选择框 const dropdown = document.createElement('select'); dropdown.className = 'custom-select'; // 添加自定义样式类 dropdown.id = 'dropdown'; // 添加 id 属性 // 构建 option 标签 var options = ''; siteMenu.forEach(function (item) { if (mid == item.id) { options += ``; } else { options += ``; } }); // 将生成的 option 标签添加到 dropdown 中 dropdown.innerHTML = options; // 将下拉选择框插入到目标元素之后 targetElement.insertAdjacentElement('afterend', dropdown); dropdownel = document.getElementById('dropdown'); // 监听 change 事件 dropdownel.addEventListener('change', function () { // 获取选中的 option var selectedOption = dropdownel.options[dropdownel.selectedIndex]; // 获取选中的 id 和 uri var id = selectedOption.value; var uri = selectedOption.getAttribute('uri'); if (id > 0) { // 生成跳转的 URL var redirectUrl = `?mid=${id}&uri=${encodeURIComponent(uri)}`; // 跳转到生成的 URL window.location.href = redirectUrl; } }); }); //更新时调用接口保存数据 editor.on('update', () => { const html = editor.getHtml(); // 你可以在这里添加自定义逻辑 //ajax提交数据 $.ajax({ url: '/dist/visual-editor/preview-save', type: 'POST', headers: { 'X-CSRF-TOKEN': csrfToken, }, data: { // 发送数据 html: html }, success: function (res) { if (res.status != 1) { //alert('save error'); } }, error: function (err) { alert(err); } }); }); // 上传图片时触发 var layer = layui.layer; var loadIndex = null; editor.on('asset:upload:start', () => { loadIndex = layer.load(0, {shade: [0.5, '#000']}); }); // The upload is ended (completed or not) editor.on('asset:upload:end', () => { layer.close(loadIndex); });