|
@@ -0,0 +1,273 @@
|
|
|
+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: '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
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 创建 GrapesJS 编辑器实例
|
|
|
+const editor = grapesjs.init({
|
|
|
+ container: '#gjs', // 指定编辑器容器的 DOM 元素
|
|
|
+ fromElement: true, // 从 DOM 元素中加载初始内容
|
|
|
+ height: '100%', // 设置编辑器的高度
|
|
|
+ width: '100%', // 设置宽度自适应
|
|
|
+ storageManager: false,
|
|
|
+ panels: panelsConfig,
|
|
|
+ plugins: [myNewComponentTypes],
|
|
|
+ canvas: {
|
|
|
+ // 禁用对所有元素的选择
|
|
|
+ selectorManager: {
|
|
|
+ // 允许选择特定类名的元素
|
|
|
+ selector: '.your-class-name',
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+const am = editor.AssetManager;
|
|
|
+// 锁定整个画布
|
|
|
+editor.getWrapper().set({ locked: true });
|
|
|
+
|
|
|
+// 遍历所有组件并解锁具有edit属性的组件
|
|
|
+const edit_classes = ['gjs_edit','btn-container']; // 定义需要解锁的组件类名
|
|
|
+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').gjs_edit == 'true') {
|
|
|
+ component.set({ locked: false });
|
|
|
+ component.setStyle({
|
|
|
+ border: '2px 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');
|
|
|
+ // 获取 .gjs-cv-canvas-bg 元素
|
|
|
+ canvasBg = document.querySelector('.gjs-cv-canvas');
|
|
|
+ canvasBg.classList.remove('gjs-cv-canvas-bg');
|
|
|
+
|
|
|
+ var elements = document.querySelectorAll('.gjs-pn-views-container');
|
|
|
+ elements.forEach(function(element) {
|
|
|
+ element.style.display = 'block'; // 或者 'flex',取决于你希望如何显示这些元素
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ canvasBg = document.querySelector('.gjs-cv-canvas');
|
|
|
+ canvasBg.classList.add('gjs-cv-canvas-bg');
|
|
|
+ var elements = document.querySelectorAll('.gjs-pn-views-container');
|
|
|
+ elements.forEach(function(element) {
|
|
|
+ element.style.display = 'none'; // 或者 'flex',取决于你希望如何显示这些元素
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 双击图片时弹出图片管理器
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ //其他
|
|
|
+});
|
|
|
+
|
|
|
+// 监听 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 += `<option value="${item.id}" uri="${item.url}" selected>${item.title}</option>`;
|
|
|
+ } else {
|
|
|
+ options += `<option value="${item.id}" uri="${item.url}">${item.title}</option>`;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 将生成的 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();
|
|
|
+ // 你可以在这里添加自定义逻辑
|
|
|
+ console.log('GrapesJS updated the editor content', html);
|
|
|
+});
|