diff --git a/index.js b/index.js index 7d8ff14..aad5565 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,39 @@ -import { div, span, pre } from './main.js' +import { div, span, pre, h1, p, ul, li } from './main.js' -document.body.appendChild(div.w(128).h(64).childs([ +// 动画三阶段 +// 1. 初始状态 +// 2. 变化过程 +// 3. 结束状态 +// 4. 触发事件 +// 5. 中途变化 + +// cursor-pointer overflow-clip hover:text-pink-500 +document.body.appendChild(div.cursor_pointer.bg_red_500.overflow_clip.w_128.h_64.childs([ + h1.m('2rem').p({ top: '2rem' }).text('Widgets!'), + p.m('2rem').p({ top: '2rem' }).text('是什么, 为什么, 怎么做?'), + ul.m('2rem').p({ top: '2rem' }).childs([ + li.text('我们需要让事情变简单和直观, 只使用纯粹的js代码, 整个项目只有js文件, 而不必在 js 和 html 和 css 文件之间跳来跳去'), + li.text('汲取了 pug 和 winicss 的灵感, 以及 flutter 的嵌套布局方式, pug 减少 html 冗余, winicss 减少 css 冗余'), + li.text('这个库的唯一作用就是给dom对象添加了额外的操作方法, 且每个方法的返回值都是dom自身, 从而实现对dom对象的链式操作') + ]), + //span.css('bg-red').m('2rem').p({ top: '2rem' }).text('Hello world!'), + new span({ textContent: 'Hello world!' }), + + // 三类参数 + p.text(` + span 是一个类(class), 直接实例化 (new span()) 将创建一个 span 元素(DOM对象). 实例化时可以传递参数, 它对应DOM对象的属性. + span.m('2rem').p({ top: '2rem' }).text('Hello world!') 是一个链式操作, 每个链式操作都是DOM对象的方法缩写. 不同的是它返回的是DOM对象自身. + span.cursor_pointer.color_ppp.w(128).h(64).childs([span.text('Hello world!')]) 是预定义的链式操作, 在执行函数方法前的静态属性调用并没有实例化对象, 只是缓存了属性值. 当对象被实例化时, 静态属性会被应用到实例对象上. 而静态属性的语法对应 tailwindcss 的类名. + `) +])) + +// 使用 js 文件作为组件管理代码 +document.body.appendChild(div.cursor_pointer.color_ppp.w(128).h(64).childs([ span.m('2rem').p({ top: '2rem' }).text('Hello world!'), new span({ textContent: 'Hello world!' }), ])) fetch('/index.js').then(res => res.text()).then(text => { + text = text.replace(/from "\/main.js"/g, "from '@laniakeasupercluster/widgets'") document.body.appendChild(pre.p('2rem').bg('#ececec').text(text.substring(0, text.indexOf('fetch')))) }) diff --git a/main.js b/main.js index 01cbd3f..f1cfd21 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,4 @@ -export function createElement({ innerText, innerHTML, textContent, readOnly, children = [], dataset, style, classList = [], ...attributes }, tagName = 'div') { +export function createElement({ innerText, innerHTML, textContent, readOnly, children = [], dataset, style, classList = [], ...attributes }, tagName = 'div', __name = '') { const element = document.createElement(tagName) for (const key in attributes) { if (key.startsWith('on')) element[key] = attributes[key] // 如果是事件则直接赋值 @@ -13,9 +13,100 @@ export function createElement({ innerText, innerHTML, textContent, readOnly, chi if (readOnly) element.readOnly = readOnly if (children) children.forEach(child => element.appendChild(child)) + // 生成样式 + console.log('name:', __name) + + // 分解类名, 生成样式, 直接将样式赋予元素 + __name.split('.').map(name => name.split('_')).forEach(item => { + console.log('item:', item) + // 两个参数的情况下, 第一个参数是样式名, 第二个参数是样式值 + if (item.length === 2) { + const [key, value] = item + + if (key === 'cursor') { + element.style.cursor = value + return + } + if (key === 'overflow') { + element.style.overflow = value + return + } + if (key === 'bg') { + element.style.backgroundColor = value + return + } + + const styleMap = { + 'w': ['width'], + 'h': ['height'], + 'p': ['padding'], + 'm': ['margin'], + 'pt': ['paddingTop'], + 'pl': ['paddingLeft'], + 'pr': ['paddingRight'], + 'pb': ['paddingBottom'], + 'mt': ['marginTop'], + 'ml': ['marginLeft'], + 'mr': ['marginRight'], + 'mb': ['marginBottom'], + 'px': ['paddingLeft', 'paddingRight'], + 'py': ['paddingTop', 'paddingBottom'], + 'mx': ['marginLeft', 'marginRight'], + 'my': ['marginTop', 'marginBottom'] + } + + if (styleMap.hasOwnProperty(key)) { + styleMap[key].forEach(style => { + element.style[style] = isNaN(value) ? value : `${value}px` + }) + return + } + + if (key === 'radius') { + element.style.borderRadius = value + return + } + if (key === 'font') { + element.style.font = value + return + } + } + + // 三个参数的情况下, 第一个参数是样式名, 第二个参数是样式, 第三个参数是数值 + if (item.length === 3) { + if (item[0] === 'color') { + element.style.color = item[1] + return + } + } + // px py mx my + // p-1 p-2 p-3 p-4 + // m-1 m-2 m-3 m-4 + // w h z bg + }) + + //const className = __name.split('.').map(name => name.replace(/_/g, '-')).join(' ') + //console.log('className:', className, element.classList) + //if (className) element.classList.add(...className.split(' ')) + //// 获取全局样式表, 如果不存在则添加一个 + //if (!document.styleSheets.length) { + // document.head.appendChild(document.createElement('style')) + //} + //// 检查全局是否已经存在 cursor-pointer, 如果不存在则添加 + //const rules = Array.from(document.styleSheets[0].cssRules) + //const styleSheet = document.styleSheets[0] + //if (!rules.some(rule => rule.selectorText === '.cursor-pointer')) { + // styleSheet.insertRule('.cursor-pointer { cursor: pointer; }') + // console.log('insertRule:', styleSheet.cssRules) + //} + // 为元素添加链式操作方法 element.w = (width) => { element.style.width = width; return element } element.h = (height) => { element.style.height = height; return element } + element.x = (left) => { element.style.left = left; return element } // 以居中线对齐(flex) + element.y = (top) => { element.style.top = top; return element } // 以居中线对齐(flex) + element.z = (zIndex) => { element.style.zIndex = zIndex; return element } + element.cursor = (cursor) => { element.style.cursor = cursor; return element } element.text = (text) => { element.textContent = text; return element } element.html = (html) => { element.innerHTML = html; return element } element.childs = (childs) => { childs.forEach(child => element.appendChild(child)); return element } @@ -60,9 +151,9 @@ export class BaseElement { static childs(childs) { return createElement({ children: childs }, this.name) } - static w(width) { + static w(width, __name) { if (typeof width === 'number') width = width + 'px' - return createElement({ style: { width } }, this.name) + return createElement({ style: { width } }, this.name, __name) } static h(height) { if (typeof height === 'number') height = height + 'px' @@ -131,7 +222,26 @@ export class BaseElement { } } -export class div extends BaseElement { +export const proxy = new Proxy(BaseElement, { + get(target, property) { + if (property in target) { + // 如果调用的是静态方法则在结尾附上 __name 参数 + const __name = this.__name || '' + if (typeof target[property] === 'function') { + return function (...args) { + return target[property](...args, __name) + } + } + return target[property] + } else { + const __name = this.__name ? this.__name + '.' + property : property + console.log('__name:', __name) + return new Proxy(target, { __name, get: this.get }) + } + } +}) + +export class div extends proxy { constructor(options) { super(options) }