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: '#mtb_visual_editor', // 指定编辑器容器的 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 dotted #f08300'
});
} else {
component.setStyle({
border: '1px dotted #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;
}
});
//发布按钮
customSelect = document.querySelector('.custom-select');
// 创建 sendButton 按钮
const sendButton = document.createElement('button');
sendButton.textContent = publishBtnName; // 按钮文本
sendButton.classList.add('send-button');
sendButton.classList.add('layui-btn');
sendButton.classList.add('layui-btn-radius');
sendButton.classList.add('layui-btn-radius');
sendButton.style = 'margin-left:10px;height:25px;line-height:25px;padding:0 10px;vertical-align:unset;'; // 添加样式(可选)
customSelect.insertAdjacentElement('afterend', sendButton);
//关闭loading
layer.close(loadIndex);
});
//更新时调用接口保存数据
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);
}
});
});
// 上传图片时触发loading效果
editor.on('asset:upload:start', () => {
loadIndex = layer.load(0, {shade: [0.5, '#000']});
});
editor.on('asset:upload:end', () => {
layer.close(loadIndex);
});
// 图片懒加载
layui.use('flow', function(){
var flow = layui.flow;
//当你执行这样一个方法时,即对页面中的全部带有 lay-src 的 img 元素开启了懒加载(当然你也可以指定相关 img)
flow.lazyimg();
});