Appearance
自定义指令集
点击元素外部
实现思路:
在指令的 bind 的时候,拿到绑定的 DOM 节点,利用Node.contains,并为 document 绑定 click 事件,当点击的元素不是绑定的 DOM 的子集时,Node.contains
返回 false,即点击了元素外部;
export default {
bind: function (el, binding) {
function documentHandler(e) {
// node.contains可判断节点与指定节点是否存在包含关系
if (el.contains(e.target)) return false;
if (binding.expression) {
binding.value(e);
}
el.__vueClickOutside__ = documentHandler;
document.addEventListener("click", documentHandler);
}
},
unbind: function (el) {
// 及时销毁事件和无效引用,避免内存泄漏
document.removeEventListener("click", el.__vueClickOutside__);
delete el.__vueClickOutside__;
},
};
锚点时间转换
实现思路:
为节点绑定定时器,每秒计算锚点时间差值,并更新节点内容;
const Time = {
// 获取当前时间戳
getUnix: function () {
var date = new Date();
return date.getTime();
},
// 获取今天0点0分0秒的时间戳
getTodayUnix: function () {
var date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
// 获取今年1月1日0点0分0秒的时间戳
getYearUnix: function () {
var date = new Date();
date.setMonth(0);
date.setDate(1);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
// 获取标准年月日
getLastDate: function (time) {
var date = new Date(time);
var month =
date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1;
var day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
return date.getFullYear() + "-" + month + "-" + day;
},
// 转换时间
getFormatTime: function (timestamp) {
var now = this.getUnix(); //当前时间戳
var today = this.getTodayUnix(); //今天0点时间戳
var year = this.getYearUnix(); //今年0点时间戳
var timer = (now - timestamp) / 1000; // 转换为秒级时间戳
var tip = "";
if (timer <= 0) {
tip = "刚刚";
} else if (Math.floor(timer / 60) <= 0) {
tip = "刚刚";
} else if (timer < 3600) {
tip = Math.floor(timer / 60) + "分钟前";
} else if (timer >= 3600 && timestamp - today >= 0) {
tip = Math.floor(timer / 3600) + "小时前";
} else if (timer / 86400 <= 31) {
tip = Math.ceil(timer / 86400) + "天前";
} else {
tip = this.getLastDate(timestamp);
}
return tip;
},
};
export default {
bind: function (el, binding) {
el.innerHTML = Time.getFormatTime(binding.value * 1000);
el.__timeout__ = setInterval(function () {
el.innerHTML = Time.getFormatTime(binding.value * 1000);
}, 60000);
},
unbind: function (el) {
clearInterval(el.__timeout__);
delete el.__timeout__;
},
};
知识点
渲染函数
渲染函数
提到渲染函数就不由得想起 VNode,Vue 将渲染函数转换为 VNode,VNode 是一个对象,包含了节点名称、属性、子节点等信息,不管是单文件组件(SFC),还是说 JSX 组件、render 函数、函数组件,其最终的编译结果都是 VNode 数组(VNode 是虚拟 DOM 的组成单位)。
官网中介绍渲染函数的例子中,提到了动态组件,类似于内置的component
组件(其实不是类似,component 组件就是组件式的渲染函数),根据这个动态组件实现方式,常见的一些表单、表格组件就可以使用这种方式来实现业务封装,如:
Vue.component("dynamicForm", {
data() {
return {
formList: [
{ comp: "ElInput", props: { type: "text" } },
{
comp: "ElButton",
props: { type: "primary" },
on: { click: this.handleSubmit },
},
],
};
},
render(createElement) {
return createElement(
"div",
{},
this.formList.map((item) => {
return createElement(item.comp, {
props: item.props || {},
on: item.on || {},
});
})
);
},
});