* 能够在保留 <Boolean> (false) 的前提下过滤 <undefined> 与 <null> 类型。
* 无法识别 <Symbol> 与 <Function> 类型,这些类型将会与 <undefined> 、<null> 一样会被忽略。
/** * [对象 -> 字符串] * @param o [对象数据] * @param o ({ key: value[] }: abled) */ function obj2str(o){ const result = [] for (const prop in o) { if(hasValue(o[prop])) { if(o[prop].length && o[prop] instanceof Array) { result.push(`${prop}: ${arr2str(o[prop])}`) } else { switch (typeof o[prop]) { case 'string': result.push(`${prop}: '${o[prop]}'`) break case 'number': result.push(`${prop}: ${o[prop] + ''}`) break case 'boolean': result.push(`${prop}: ${o[prop].toString()}`) break case 'object': result.push(`${prop}: ${obj2str(o[prop])}`) break } } } } return `{ ${result.join(', ')} }` } /** * [数组 -> 字符串] * @param a [数组数据] * @param a ([{ key: value }]: abled) */ function arr2str(a) { const result = [] a.forEach(item => { if(hasValue(item)) { if(item.length && item instanceof Array) { arr2str(item) } else { switch (typeof item) { case 'string': result.push(`'${item}'`) break case 'number': result.push(item + '') break case 'boolean': result.push(item.toString()) break case 'object': result.push(obj2str(item)) break } } } }) return `[ ${result.join(', ')} ]` } /** * [检验值是否存在] * @param v [被检验值] * @param v ([<boolean> (false): abled) */ function hasValue(v) { let flag = !v && typeof v !== 'boolean' return !flag }
我在使用 ES6: class something extends HTMLElement 编写 shadowDOM 组件时踩的坑。
当我使用 innerHTML 创建一个 HTML 树结点: `<div onclick="myFn(${arg})">` 并点击触发时:
查看 DOM 树:
可预见的, 该参数仅仅被 innerHTML 转译成成了一段字符串,如下示例:
那么当我们想在 shadowDOM 上绑定自定义属性时,便难以将其传递给该函数的形参。
我们知道 onclick 事件的 this 会指向该 DOM 的结点,而不是继承了 HTMLElement 的 Class,无法获取类内部绑定的变量。
这时我尝试将 onclick 函数中传递的参数改为 `<div onclick="myFn({ msg: 'success!' })">`,浏览器反而能成功返回:
可以看出在 innerHTML API 中引用 Function 并传入实参本身就不被建议与支持,也许现在我们更加了解浏览器与 DOM 了。
但当我想要完整的传入一个对象 / 数组变量时,可能就要将其转换为字符串后传入,才可被浏览器解析与识别:
但如果无法改变 Class 内部的 props 变量,这样仅仅取值而不通知且无法改变宿主的拿来主义,反而让ShadowDOM变得更局限。
反而需要另一个普通 Class 作为中继器来完成更多的处理,这并不能发挥 Class 的全部作用,这是一个非常浪费的行为,也是框架开发者们拥抱 Functional Component 而非 Class Component 的主要理由,当然大多框架的实现与 shadowDOM 无关,如 Vue 的 virtualDOM 与 React 的 JSX 语法,shadowDOM 只是更便于原生 JS 实现组件化的手段之一。
由此可得在编写 ShadowDOM 组件时,应多利用 createElement 这样的 API 而非 innerHTML...