自定义指令
v-model、v-bind、v-on、v-show、v-if 等这些由 v- 开头的都是Vue中的核心内置指令,他们的作用就是在元素的整个生命周期的某个阶段对DOM进行内容或者样式上的操作。
1.全局自定义指令
(1)定义全局自定义指令 以下就是一个自定义指令让文本框获取焦点的实例:
//自定义全局的指令
Vue.directive('focus', {
//第一个参数永远是el,表示原生的js对象
bind: function (el) { //当指令绑定到元素上的时候,会立即执行bind函数,只执行一次,此时元素还没有插入到DOM中,focus聚焦此时不会生效
el.focus()
},
inserted: function (el) { //当元素插入到DOM中的时候,会执行inserted函数,只执行一次
el.focus()
},
updated: function () { //当VNode的时候,会执行updated函数,可能出发多次
}
});
<input type="text" class="form-control" v-model="keywords" v-focus">
2.私有自定义指令
(1)和私有自定义过滤器类似,也是将作为和methods平级的属性定义在VM的实例中
directives: {
'fontweight': {
bind: function (el, bingding) {
el.style.fontWeight = bingding.value;
}
},
'fontsize': function (el, bingding) { //这个function等同于把代码写到了bind和update中去
el.style.fontSize = parseInt(bingding.value) + 'px';
}
}
(2)在dom中使用该指令
{{date | dateFormat}}
钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
1. inserted:
被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
2. bind:
只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
3. update:
所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
4. componentUpdated:
指令所在组件的 VNode 及其子 VNode 全部更新后调用。
5. unbind:
只调用一次,指令与元素解绑时调用。
钩子函数参数
1. el:
指令所绑定的元素,可以用来直接操作 DOM 。
2. binding:
- 一个对象,包含以下属性:
- name:指令名,不包括 v- 前缀。
- value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
- oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 “1 + 1”。
- arg:传给指令的参数,可选。例如 v-my-directive: foo 中,参数为 “foo”。
- modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
3. vnode:
Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
4. oldVnode:
上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
注意:除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
自定义指令分享
自定义指令 点击 元素内部外部
<div V-click-outside>
<input type="text" :value="formatDate">
<div class="panneu" v-if="isVisible">
content
<button></button>
/div>
</div>
directives:{
clickOutside:[ // 指令的生命周期
bind(el,bindings,vnode){ // context
// 把事件绑定给document上 看一下点击的是否是当前这个元素内部let handler = (e)=>[
if(el.contains(e.target)){
// 判断一下是否当前面板已经显示出来了if(!vnode.context.isVisible){vnode.context.focus();
}elsef
if(vnode.context.isVisible){vnode.context.blur();
el.handler = handler;
document.addEventListener('click',handler)
unbind(el){
document.removeEventListener('click',el.handler)
}
}
长摁事件
<div v-longpress="longPressHandler"/>
directives: {
longpress: {
inserted: function (el, binding, vnode) {
let pressTimer = null;
el.addEventListener("mousedown", (e) => {
pressTimer = setTimeout(() => {
binding.value();
}, 300);
});
el.addEventListener("mouseup", (e) => {
clearTimeout(pressTimer);
});
},
},
},
右键显示 全局点击左键关闭
<div
class="treeDiv"
v-infinite-scroll="load"
infinite-scroll-immediate="false"
>
<p
v-for="item in data"
:key="item.tableNames"
:class="tableName == item.tableNames ? 'activeP' : ''"
@click="handleNodeClick(item)"
@contextmenu.prevent="RightNodeClick(item)"
v-Rclick
>
{{ item.tableNames }}
</p>
<div class="modelDiv" ref="modelDiv">
<p @click="rightLeftClick">设计表</p>
</div>
</div>
directives: {
Rclick: {
// 自定义指令
inserted: function (el, _binding, vnode) {
let that = vnode.context; // 当前vue 实例
el.oncontextmenu = function (e) {
e.preventDefault();
window.oncontextmenu = function (e) {
let ny = e.clientY;
let nx = e.clientX;
that.$refs.modelDiv.style.top = ny + "px";
that.$refs.modelDiv.style.left = nx + "px";
that.$refs.modelDiv.style.display = "block";
window.oncontextmenu = function () {}; // 指定元素使用完后 初始化 windowoncontextmenu 事件
};
window.onclick = function (e) {
that.$refs.modelDiv.style.display = "none";
};
};
},
},
}
自定义 拖拽边框放大缩小 和 自定义右键点击 然后显示在对应位置上
之间写项目的时候有遇到 精简代码 放在这
<template>
<el-container style="overflow: hidden">
<el-aside :width="asideWith">
<el-input v-model="inputVal" placeholder="请输入内容"></el-input>
<div
class="treeDiv"
v-infinite-scroll="load"
infinite-scroll-immediate="false"
>
<p
v-for="item in data"
:key="item.tableNames"
@click="handleNodeClick(item)"
@contextmenu.prevent="RightNodeClick(item)"
v-Rclick
>
{{ item.tableNames }}
</p>
<div class="modelDiv" ref="modelDiv">
<p @click="rightLeftClick">设计表</p>
</div>
</div>
<div class="borDiv" v-drag></div>
</el-aside>
<el-container style="height: 100vh; overflow: hidden">
<el-header :height="HeaderWith">
<div
class="headerBox"
:style="{ height: HeaderWith }"
>
<div class="flex-between">
<div>
<el-button type="primary">搜索</el-button>
</div>
</div>
<div class="headerDiv" v-drag></div>
</div>
</el-header>
<el-main>
<!-- 右键 设计表 -->
<div class="mainDiv" >
</div>
</el-main>
</el-container>
</el-container>
</template>
<script>
//工作流路径的配置
export default {
name: "DataVisualizationTable",
data() {
return {
inputVal:'',
asideWith: "400px", // 左侧栏宽度
HeaderWith: "200px", // 头部高度
showLeftBox: true, // 控制左键点击时盒子显示
data: [{tableNames:'asdasd'}], // 左侧数据
};
},
methods: {
load(){
},
async handleNodeClick(data) {
},
async rightLeftClick() {
},
RightNodeClick(item) {
},
},
directives: {
drag: {
// 自定义指令 拖拽修改 左侧宽度
inserted: function (el, _binding, vnode) {
let name = el.className;
let x = 0;
let y = 0;
let l = 0;
let t = 0;
let isDown = false;
let that = vnode.context; // 当前vue 实例
//鼠标按下事件
el.onmousedown = function (n) {
//获取x坐标和y坐标
x = n.clientX;
y = n.clientY;
//获取左部和顶部的偏移量
l = el.offsetLeft;
t = el.offsetTop;
//开关打开
isDown = true;
//鼠标移动
window.onmousemove = function (e) {
if (isDown == false) return;
e.preventDefault();
//获取x
//计算移动后的左偏移量
let nl = e.clientX - (x - l);
let nt = e.clientY - (y - t);
if (name == "borDiv") {
if (nl > 100) that.asideWith = nl + "px";
} else {
if (nt > 87) that.HeaderWith = nt + "px";
}
};
//鼠标抬起事件
window.onmouseup = function () {
if (isDown === false) return;
//开关关闭
isDown = false;
};
};
},
},
Rclick: {
// 自定义指令 拖拽修改 左侧宽度
inserted: function (el, _binding, vnode) {
let that = vnode.context; // 当前vue 实例
el.oncontextmenu = function (e) {
e.preventDefault();
window.oncontextmenu = function (e) {
let ny = e.clientY;
let nx = e.clientX;
that.$refs.modelDiv.style.top = ny + "px";
that.$refs.modelDiv.style.left = nx + "px";
that.$refs.modelDiv.style.display = "block";
window.oncontextmenu = function () {}; // 指定元素使用完后 初始化 window oncontextmenu 事件
};
window.onclick = function (e) {
that.$refs.modelDiv.style.display = "none";
};
};
},
},
},
};
</script>
<style lang="scss" scoped>
.el-aside {
position: relative;
padding: 10px 5px 0 5px;
text-align: center;
height: 100vh;
overflow: visible;
::v-deep .el-input {
margin: 0 0 10px 0;
input {
padding: 0;
}
}
.treeDiv {
height: 94vh;
overflow: auto;
.modelDiv {
position: absolute;
width: 100px;
height: 30px;
background: rgba(193, 193, 193, 0.8);
display: none;
z-index: 9;
p {
text-align: center;
padding: 2px;
}
}
p {
padding: 5px 0;
text-align: left;
&:hover {
cursor: pointer;
background: rgba(245, 238, 238, 0.5);
}
}
}
.borDiv {
position: absolute;
top: 0;
right: 0;
width: 3px;
height: 100%;
background: #333;
cursor: e-resize;
}
}
.el-header {
position: relative;
overflow: hidden;
.headerBox {
height: 200px;
overflow: auto;
padding-top: 10px;
.headerDiv {
position: absolute;
bottom: 0;
right: 0;
width: 100%;
height: 3px;
background: #333;
cursor: n-resize;
z-index: 9;
}
}
}
.el-main {
padding: 0 10px;
.mainDiv {
margin-top: 10px;
}
}
.flex {
width: 60%;
display: flex;
justify-content: space-around;
align-items: end;
::v-deep .el-input,
.el-select {
margin: 5px 10px 0 0;
}
::v-deep .el-checkbox__inner {
margin: 5px;
}
}
.flex-between {
width: 100%;
display: flex;
justify-content: space-between;
}
::v-deep .el-table--border .el-table__cell {
background: #fff !important;
}
::v-deep .el-table__body-wrapper {
height: 568px !important;
}
::v-deep .el-table__empty-block {
justify-content: flex-start;
}
</style>