设计模式-发布订阅.js
class Sub {
construct(){
this.obj = {};
this.events = {
key1: [],
key2: [],
}
}
change(key, value) {
this.obj[key] = value
if (this.events[key]) {
this.events[key].forEach(fn => fn(value));
}
}
watch(key, fn = () => {}) {
if (this.events[key]) {
this.events[key].push(fn);
} else {
this.events[key] = [fn];
}
}
unWatch(key, fn) {
if (!this.events[key]) return;
// 此处应做严谨的事件相等判断
this.events[key].filter(a => a !== fn);
}
}
设计模式-实现模版渲染.js
// problem
let template = "我是{{name}},年龄{{age}},性别{{sex}}";
let data = {
name: "姓名",
age: 18,
};
render(template, data); // 我是姓名,年龄18,性别undefined
// answer
function render(template, data) {
const reg = /\{\{(\w+)\}\}/; // 模板字符串正则
if (reg.test(template)) {
// 判断模板里是否有模板字符串
const name = reg.exec(template)[1]; // 查找当前模板里第一个模板字符串的字段
template = template.replace(reg, data[name]); // 将第一个模板字符串渲染
return render(template, data); // 递归的渲染并返回渲染后的结构
}
return template; // 如果模板没有模板字符串直接返回
}
设计模式-实现虚拟DOM.js
// problem
let domNode = {
tagName: "ul",
props: { class: "list" },
children: [
{
tagName: "li",
children: ["item1"],
},
{
tagName: "li",
children: ["item1"],
},
],
};
// 构建一个 render 函数,将 domNode 对象渲染为 以下 dom
<ul class="list">
<li>item1</li>
<li>item2</li>
</ul>;
// answer
function render(domNode) {
if (!domNode) return document.createDocumentFragment();
let $el;
if (typeof domNode === "object") {
$el = document.createElement(domNode.tagName);
if (domNode.hasOwnProperty("props")) {
for (let key in domNode.props) {
$el.setAttribute(key, domNode.props[key]);
}
}
if (domNode.hasOwnProperty("children")) {
domNode.children.forEach((val) => {
const $childEl = render(val);
$el.appendChild($childEl);
});
}
} else {
$el = document.createTextNode(domNode);
}
return $el;
}