You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

614 lines
23 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

(function () {
let main = {
grid: null,
initData: null,
};
let welcome = {
grid: null,
initData: null,
};
let currentComponent = null;
let cellHeight = 60;
// 让gridstack知道如何渲染组件children中的content直接渲染html
GridStack.renderCB = function (el, w) {
el.innerHTML = w.content;
};
GridStack.setupDragIn('#components-panel .component-item', undefined, [
{
w: 2,
h: 2,
type: 'image',
name: '图片',
background: '#fff',
image: '',
eventsType: 'click',
eventsAction: '',
defaultFocus: false,
leftId: '',
rightId: '',
upId: '',
downId: '',
focusedStyle_background: '',
focusedStyle_border_width: 0,
focusedStyle_border_color: '',
focusedStyle_scale: 1,
},
{
w: 2,
h: 1,
type: 'text',
childrenType: '',
name: '文本',
background: '#fff',
fontSize: 14,
color: '#333',
text: '文本',
fontWeight: 'normal',
eventsType: 'click',
eventsAction: '',
defaultFocus: false,
leftId: '',
rightId: '',
upId: '',
downId: '',
focusedStyle_background: '',
focusedStyle_border_width: 0,
focusedStyle_border_color: '',
focusedStyle_scale: 1,
},
]);
// 生成唯一id
var generateUniqueId = function () {
const timestamp = Date.now().toString(36);
const randomNum = Math.random().toString(36).substring(2);
return timestamp + randomNum;
};
// 判断是画布还是组件
var isScreen = function (type) {
return type === 'screen';
};
/** 初始化 */
var init = function (type, self) {
const initDataStorage = localStorage.getItem(`${type}Data`);
if (!initDataStorage) {
self['initData'] = {
type: 'screen',
id: `grid_${generateUniqueId()}`,
children: [],
version: '1.0.0',
width: 1920,
height: 1080,
background: '#e2e2e2',
image: '', // 为画布添加image属性
};
} else {
self['initData'] = JSON.parse(initDataStorage);
conputedInitData('init', self);
}
self['initData'].el = document.getElementById(`${type}-screen`);
console.log(self['initData'], `${type}Data`);
// 初始化时应用画布背景
const canvasId = `${type}-screen`;
if (self.initData.image) {
$('#' + canvasId)
.css('background-image', `url(${self.initData.image})`)
.css('background-size', 'cover');
} else if (self.initData.background) {
$('#' + canvasId).css('background-color', self.initData.background);
}
self['grid'] = GridStack.init(
{
// 一行高度
cellHeight,
// 间距
margin: 0,
minRow: Math.floor(1080 / 2 / cellHeight),
maxRow: Math.floor(1080 / 2 / cellHeight),
acceptWidgets: true,
float: true,
removable: '#trash',
// subGridOpts: subOptions,
// subGridDynamic: true,
children: self['initData'].children,
},
`#${type}-screen`
);
// console.log(self['grid'], `${type}.grid实例`);
// grid.load(initData.children);
self['grid'].engine.nodes.forEach((item) => {
handleAddComponent(item, self);
});
self['grid'].on('added', function (_event, itemArray) {
console.log(itemArray, '这里触发了添加了added事件');
itemArray.forEach((item) => {
handleAddComponent(item, self);
});
});
self['grid'].on('removed', function (_event, itemArray) {
console.log(itemArray, '这里触发了移除removed事件');
itemArray.forEach((item) => {
handleRemoveComponent(item);
});
});
};
// 处理添加组件之后的操作
var handleAddComponent = (component, self) => {
if (!component.id) {
component.id = `${component.type}_${generateUniqueId()}`;
}
setComponentView(component);
component.el.addEventListener('click', (e) => {
e.stopPropagation();
console.log(isScreen(component.type) ? `点击画布` : `点击组件`, component);
if (currentComponent && currentComponent.id === component.id) {
return;
}
// 清除之前选中组件的获取焦点后的样式
clearOldFocusStyle();
currentComponent = component;
// 右侧显示组件属性列表
if (!$('#props-panel').find('form').is(':visible')) {
$('#props-panel').find('.wait-box').hide();
$('#props-panel').find('form').show();
}
// 将当前选中组件的属性显示在右侧列表中
setCurrentComponentProps(currentComponent);
// 非画布时设置
if (!isScreen(component.type)) {
// 设置当前选中组件的获取焦点后的样式
setCurrentFocusStyle();
// 设置上下左右移动组件ID
setMoveComponentId(currentComponent, self);
}
});
};
var clearOldFocusStyle = function () {
if (currentComponent && !isScreen(currentComponent.type)) {
let el = $(currentComponent.el).find('.grid-stack-item-content');
el.css('background', '');
if (currentComponent.image) {
el.find('img').attr('src', currentComponent.image);
}
if (currentComponent.background) {
el.css('background', currentComponent.background);
}
el.css('border-color', '');
el.css('border-width', '');
el.css('transform', '');
}
};
var setCurrentFocusStyle = function () {
if (currentComponent && !isScreen(currentComponent.type)) {
let el = $(currentComponent.el).find('.grid-stack-item-content');
if (currentComponent.focusedStyle_background) {
el.css('background', currentComponent.focusedStyle_background);
}
el.css('border-color', currentComponent.focusedStyle_border_color);
el.css('border-width', currentComponent.focusedStyle_border_width + 'px');
el.css('transform', `scale(${currentComponent.focusedStyle_scale})`);
}
};
// 设置上下左右移动组件ID
var setMoveComponentId = function (component, self) {
const allComponents = self['grid'].save();
if (allComponents.length <= 1) {
return;
}
setMoveComponentHtml('leftId', component, allComponents);
setMoveComponentHtml('rightId', component, allComponents);
setMoveComponentHtml('upId', component, allComponents);
setMoveComponentHtml('downId', component, allComponents);
};
var setMoveComponentHtml = function (idName, component, allComponents) {
let componentsHtml = [{ value: '', text: '请选择' }];
allComponents
.filter((item) => item.id !== component.id)
.map((item) => {
componentsHtml.push({ value: item.id, text: `${item.name}(${item.id})`, selected: item.id === component[idName] });
});
let el = $(`#${idName}`);
el.empty();
componentsHtml.forEach((item) => {
el.append(
$('<option>', {
value: item.value,
text: item.text,
selected: item.selected || false,
})
);
});
};
var handleRemoveComponent = (component) => {
if (currentComponent && currentComponent.id === component.id) {
currentComponent = null;
hidePropsPanel();
}
};
var hidePropsPanel = () => {
// 右侧显示请选择组件
if (!$('#props-panel').find('wait-box').is(':visible')) {
$('#props-panel').find('.wait-box').show();
$('#props-panel').find('form').hide();
}
};
//将当前选中组件的属性显示在右侧列表中
var setCurrentComponentProps = function (component) {
// 设置标题
$('#props-panel .panel-title span').text(isScreen(component.type) ? '画布属性' : '组件属性');
const form = $('#props-panel').find('form');
if (component.hasOwnProperty('childrenType')) {
form.find('#childrenType').val(component.childrenType);
form.find('#childrenType').parent().show();
} else {
form.find('#childrenType').parent().hide();
}
if (!isScreen(component.type)) {
form.find('#name').val(component.name);
} else {
form.find('#name').parent().hide();
}
if (component.hasOwnProperty('image')) {
form.find('#image').val(component.image);
form.find('#image').parent().show();
} else {
form.find('#image').parent().hide();
}
if (component.hasOwnProperty('background')) {
let options = {
elem: '#background',
alpha: true,
format: 'rgb',
done: function (color) {
const el = $(component.el);
let cptColor = rgbaToHex(color);
component.background = cptColor;
if (isScreen(component.type)) {
component.image = '';
}
if (!cptColor) {
if (isScreen(component.type)) {
el.css('background', 'none');
} else {
el.find('.grid-stack-item-content').css('background', 'none');
}
} else {
if (isScreen(component.type)) {
el.css('background', color);
} else {
el.find('.grid-stack-item-content').css('background', color);
}
}
},
};
if (component.background) {
options.color = component.background;
}
layui.colorpicker.render(options);
form.find('#background').parent().show();
} else {
form.find('#background').parent().hide();
}
if (component.type === 'text') {
form.find('#text').val(component.text);
form.find('#fontSize').val(component.fontSize);
form.find('#color').val(component.color);
form.find('#fontWeight').val(component.fontWeight);
form.find('#text').parent().show();
form.find('#fontSize').parent().show();
form.find('#color').parent().show();
form.find('#fontWeight').parent().show();
} else {
form.find('#text').parent().hide();
form.find('#fontSize').parent().hide();
form.find('#color').parent().hide();
form.find('#fontWeight').parent().hide();
}
if (!isScreen(component.type)) {
form.find('#eventsType').val(component.eventsType);
form.find('#eventsAction').val(component.eventsAction);
form.find('#defaultFocus').val(component.defaultFocus);
form.find('#leftId').val(component.leftId);
form.find('#rightId').val(component.rightId);
form.find('#upId').val(component.upId);
form.find('#downId').val(component.downId);
form.find('#focusedStyle_background').val(component.focusedStyle_background);
form.find('#focusedStyle_border_width').val(component.focusedStyle_border_width);
form.find('#focusedStyle_border_color').val(component.focusedStyle_border_color);
form.find('#focusedStyle_scale').val(component.focusedStyle_scale);
form.find('#eventsType').parent().show();
form.find('#eventsAction').parent().show();
form.find('#defaultFocus').parent().show();
form.find('#leftId').parent().show();
form.find('#rightId').parent().show();
form.find('#upId').parent().show();
form.find('#downId').parent().show();
form.find('#focusedStyle_background').parent().show();
form.find('#focusedStyle_border_width').parent().show();
form.find('#focusedStyle_border_color').parent().show();
form.find('#focusedStyle_scale').parent().show();
} else {
form.find('#eventsType').parent().hide();
form.find('#eventsAction').parent().hide();
form.find('#defaultFocus').parent().hide();
form.find('#leftId').parent().hide();
form.find('#rightId').parent().hide();
form.find('#upId').parent().hide();
form.find('#downId').parent().hide();
form.find('#focusedStyle_background').parent().hide();
form.find('#focusedStyle_border_width').parent().hide();
form.find('#focusedStyle_border_color').parent().hide();
form.find('#focusedStyle_scale').parent().hide();
}
};
// 定义组件设置配置策略
const componentStrategies = {
background: function (el, value, component) {
let options = {
elem: '#background',
alpha: true,
format: 'rgb',
done: function (color) {
const el = $(component.el);
let cptColor = rgbaToHex(color);
component.background = cptColor;
if (isScreen(component.type)) {
component.image = '';
}
if (!cptColor) {
if (isScreen(component.type)) {
el.css('background', 'none');
} else {
el.find('.grid-stack-item-content').css('background', 'none');
}
} else {
if (isScreen(component.type)) {
el.css('background', color);
} else {
el.find('.grid-stack-item-content').css('background', color);
}
}
},
};
if (component.background) {
options.color = component.background;
}
layui.colorpicker.render(options);
if (!isScreen(component.type)) {
if (!value) {
el.find('.grid-stack-item-content').css('background', 'none');
} else {
el.find('.grid-stack-item-content').css('background', value);
}
}
},
image: function (el, value, component) {
if (!value) return;
if (isScreen(component.type)) {
el.css('background', `url(${value}) no-repeat center center`).css('background-size', 'cover');
component.background = '';
} else {
el.find('img').attr('src', value);
}
},
fontSize: function (el, value) {
if (!value) return;
el.find('span').css('font-size', value + 'px');
},
color: function (el, value) {
if (!value) return;
el.find('span').css('color', value);
},
text: function (el, value) {
if (!value) return;
el.find('span').text(value);
},
fontWeight: function (el, value) {
if (!value) return;
el.find('span').css('font-weight', value);
},
focusedStyle_background: function (el, value, component) {
if (!value) return;
if (currentComponent && currentComponent.id === component.id) {
el.find('.grid-stack-item-content').css('background', value);
}
},
focusedStyle_border_width: function (el, value, component) {
if (!value) return;
if (currentComponent && currentComponent.id === component.id) {
el.find('.grid-stack-item-content').css('border-width', value + 'px');
}
},
focusedStyle_border_color: function (el, value, component) {
if (!value) return;
if (currentComponent && currentComponent.id === component.id) {
el.find('.grid-stack-item-content').css('border-color', value);
}
},
focusedStyle_scale: function (el, value, component) {
if (!value) return;
if (currentComponent && currentComponent.id === component.id) {
el.find('.grid-stack-item-content').css('transform', `scale(${value})`);
}
},
};
// 设置当前传递组件的视图展示
var setComponentView = function (component, fields = null) {
const el = $(component.el);
// 确定要处理的属性
const propsToHandle = fields || Object.keys(componentStrategies);
// 遍历并执行对应的策略
propsToHandle.forEach((prop) => {
if (componentStrategies[prop] && component[prop] !== undefined) {
componentStrategies[prop](el, component[prop], component);
}
});
};
// 定义映射关系元素ID -> 事件类型 -> 组件属性
const elementMappings = {
name: { event: 'blur', property: 'name' },
childrenType: { event: 'blur', property: 'childrenType' },
background: { event: 'blur', property: 'background' },
image: { event: 'change', property: 'image' },
fontSize: { event: 'blur', property: 'fontSize' },
color: { event: 'blur', property: 'color' },
text: { event: 'blur', property: 'text' },
fontWeight: { event: 'blur', property: 'fontWeight' },
eventsType: { event: 'blur', property: 'eventsType' },
eventsAction: { event: 'blur', property: 'eventsAction' },
defaultFocus: { event: 'blur', property: 'defaultFocus' },
leftId: { event: 'change', property: 'leftId' },
rightId: { event: 'change', property: 'rightId' },
upId: { event: 'change', property: 'upId' },
downId: { event: 'change', property: 'downId' },
focusedStyle_background: { event: 'blur', property: 'focusedStyle_background' },
focusedStyle_border_width: { event: 'blur', property: 'focusedStyle_border_width' },
focusedStyle_border_color: { event: 'blur', property: 'focusedStyle_border_color' },
focusedStyle_scale: { event: 'blur', property: 'focusedStyle_scale' },
};
// 统一绑定函数
var bindComponentEvents = function () {
Object.keys(elementMappings).forEach((elementId) => {
const mapping = elementMappings[elementId];
const $element = $('#' + elementId);
if ($element.length) {
// 组件名称添加失去焦点事件或者change事件
$element.off(mapping.event).on(mapping.event, function () {
const value = $(this).val();
currentComponent[mapping.property] = value;
setComponentView(currentComponent, [mapping.property]);
});
}
});
};
// 处理Tab切换的逻辑
var handleTabSwitch = function () {
$('#canvas-tabs .tab-button').on('click', function () {
var $this = $(this);
// 如果已经是激活状态,则不执行任何操作
if ($this.hasClass('active')) {
return;
}
// 处理按钮的激活状态
$this.siblings().removeClass('active');
$this.addClass('active');
// 处理画布的显示/隐藏
var tabId = $this.data('tab');
$('#' + tabId).show();
$('.grid-stack')
.not('#' + tabId)
.hide();
// 处理右侧面板的显示/隐藏
hidePropsPanel();
});
};
// 点击保存按钮处理
var handleSaveClick = function () {
$('.save-container').click(function () {
main.initData.children = main.grid.save();
welcome.initData.children = welcome.grid.save();
console.log(main.initData);
console.log(welcome.initData);
localStorage.setItem('mainData', JSON.stringify(conputedInitData('save', main)));
localStorage.setItem('welcomeData', JSON.stringify(conputedInitData('save', welcome)));
});
};
// 点击画布处理
var handleCanvasClick = function () {
handleAddComponent(welcome.initData, welcome);
handleAddComponent(main.initData, main);
};
// 保存的时候计算x,y,w,h
var conputedInitData = function (type, self) {
if (type === 'save') {
const { el, ...otherInfo } = self['initData'];
let initDataCopy = JSON.parse(JSON.stringify(otherInfo));
initDataCopy.children.forEach((item) => {
item.xCopy = item.x;
item.x = item.x * (1920 / 12);
item.yCopy = item.y;
item.y = item.y * cellHeight * 2;
item.wCopy = item.w;
item.w = item.w * (1920 / 12);
if (!item.hasOwnProperty('h')) {
item.h = 1;
}
item.hCopy = item.h;
item.h = item.h * cellHeight * 2;
item.fontSize = item.fontSize ? parseInt(item.fontSize) : item.fontSize;
});
console.log(initDataCopy);
return initDataCopy;
}
if (type === 'init') {
self['initData'].children.forEach((item) => {
item.x = item.xCopy;
item.y = item.yCopy;
item.w = item.wCopy;
item.h = item.hCopy;
});
}
};
/** 执行方法 */
$(function () {
init('welcome', welcome);
init('main', main);
// 调用绑定
bindComponentEvents();
// 处理Tab切换
handleTabSwitch();
// 处理保存按钮
handleSaveClick();
// 处理画布点击事件
handleCanvasClick();
});
})();