直接复制粘贴代码即可使用:
点击表格显示输入框,点击其它空白处消失。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<style>
table{border-right:1px solid black;border-bottom:1px solid black}
table td{border-left:1px solid black;border-top:1px solid black;}
.skyblue{
background: skyblue;
}
/*
css 注释:
只对table td设置左与上边框;
对table设置右与下边框;
为了便于截图,我们将css 注释说明换行排版
*/
</style>
</head>
<body>
钩子函数
指令定义函数提供了几个钩子函数(可选):
bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
unbind: 只调用一次, 指令与元素解绑时调用。
<div id="app">
<h2>点击表格</h2>
<div style="position: relative">
<table width="400" border="0" cellspacing="0" cellpadding="0" v-clickoutside="handleClose">
<tr>
<td width="105">站名</td>
<td width="100">网址</td>
<td width="100">说明</td>
<td width="100">说明</td>
</tr>
<tr ref="tableTr" class="table-d-tr" v-for="(item,k) in tableData" :key="k" :data-k="k">
<td style="color:#9F6CAF;font-weight:bold;padding:8px;line-height: 1.42857143;">
{{item['dataWeek']}}
</td>
<td v-for="j in 3" :data-j="j">
<span style="display: inline-block;width: 100%; height: 46px;line-height: 46px;" :class="{skyblue:item['date'+(j-1)].skyblue}"
@click="openInput(k, j, item, $event)">{{ item['date'+(j-1)].value }}</span>
</td>
</tr>
</table>
<div ref="childPopover" style="position: absolute;background: #fff;border: 1px solid blanchedalmond;text-align:center;box-sizing: border-box; box-shadow: 0px 1px 2px #9E9E9E;" v-show="childPopoverShow">
<input ref="popoverInput" type="text" style="width:60px;" v-model="popoverValue">
<div style=" margin-top: 3px;">
<button @click="applyOk">确定</button>
<button @click="applyCancel">取消</button>
</div>
</div>
</div>
</div>
<script>
Vue.directive('clickoutside', {
bind(el, binding, vnode) {
function documentHandler(e) {
// 这里判断点击的元素是否是本身,是本身,则返回
if (el.contains(e.target)) {
return false;
}
// 判断指令中是否绑定了函数
if (binding.expression) {
// 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
binding.value(e);
}
}
// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.__vueClickOutside__ = documentHandler;
document.addEventListener("click", documentHandler);
},
unbind(el, binding) {
// 解除事件监听
document.removeEventListener("click", el.__vueClickOutside__);
delete el.__vueClickOutside__;
}
})
var vm = new Vue({
el: '#app',
data: {
childPopoverShow: false,
message: '自定义指令',
color: 'red',
popoverValue: '',
handleDate: [],
handleTempDate: [],
tableData: (function () {
let n = 7;
let arrs = [];
for (let index = 0; index < n; index++) {
let arr = {
dataWeek: getWeek(index + 1),
date0: {
value: "1",
skyblue: false
},
date1: {
value: "2",
skyblue: false
},
date2: {
value: "3",
skyblue: false
}
};
arrs[index] = arr;
}
return arrs;
function getWeek(d) {
switch (d) {
case 7:
return "星期日";
break;
case 1:
return "星期一";
break;
case 2:
return "星期二";
break;
case 3:
return "星期三";
break;
case 4:
return "星期四";
break;
case 5:
return "星期五";
break;
case 6:
return "星期六";
break;
}
}
})()
},
methods: {
openInput(k, j, item, event) {
//注意:event.currentTarget
let ele = event.currentTarget;
let w = ele.parentNode.offsetWidth;
let h = ele.parentNode.offsetHeight;
let a = JSON.stringify(this.tableData);
let obj = JSON.parse(a);
let left = ele.parentNode.offsetLeft;
if (this.handleDate.length != 0) {
let oldDateName = this.handleDate[0];
let oldK = this.handleDate[1];
this.handleTempDate = ["date" + (j - 1), k];
this.handleDate.length = 0;
obj[oldK][oldDateName]["skyblue"] = false;
} else {
if (this.handleTempDate.length != 0) {
// console.log(obj)
obj[this.handleTempDate[1]][this.handleTempDate[0]]["skyblue"] = false;
}
this.handleDate = ["date" + (j - 1), k];
}
if (this.handleColumn != k) {
obj = this.clearSkyblue(obj, this.handleColumn);
this.$set(this.tableData, this.handleColumn, obj[this.handleColumn]);
}
this.popoverValue = "";
this.handleColumn = k;
obj[k]["date" + (j - 1)]["skyblue"] = true;
this.$refs["childPopover"].style.left = left - (100 - w) / 2 + "px";
this.$refs['childPopover'].style.top = h * (k + 1.5) + 'px';
this.$refs["childPopover"].setAttribute("data-x", k);
this.$refs["childPopover"].setAttribute("data-y", j);
this.childPopoverShow = true;
this.$set(this.tableData, k, obj[k]);
setTimeout(() => {
this.$refs["popoverInput"].focus();
}, 100);
},
clearSkyblue(data, k) {
// for(let i = 0;i<data.length;i++){
if (!k || k == "") return data;
let element = data[k];
for (let j = 0; j < 3; j++) {
element["date" + j]["skyblue"] = false;
}
data[k] = element;
return data;
// }
},
handleClose(e) {
var isChildPopover = this.$refs["childPopover"].contains(e.target);
if (isChildPopover) {
return false;
}
this.applyCancel();
},
applyCancel() {
this.$refs["popoverInput"].blur();
this.childPopoverShow = false;
this.cancelSkyblue();
},
cancelSkyblue() {
for (let j = 0; j < this.tableData.length; j++) {
let element = this.tableData[j];
for (let i = 0; i < 3; i++) {
element["date" + i]["skyblue"] = false;
}
}
},
applyOk() {
let k = this.$refs["childPopover"].getAttribute("data-x");
let j = this.$refs["childPopover"].getAttribute("data-y");
let obj = JSON.parse(JSON.stringify(this.tableData));
// console.log(this.popoverValue)
if (this.popoverValue < 0 || this.popoverValue > 100 || this.popoverValue == "" || !this.popoverValue) {
this.applyCancel();
// this.$alert('商品上架数量在0~100之间', '友情提示', {
// confirmButtonText: '确定',
// type: 'warning'
// });
return false;
}
obj[k]["date" + (j - 1)]["value"] = this.popoverValue;
obj[k].dataWeek = this.getWeek(Number(k) + 1);
this.$set(this.tableData, k, obj[k]);
this.applyCancel();
},
getWeek(d) {
switch (d) {
case 7:
return "星期日";
break;
case 1:
return "星期一";
break;
case 2:
return "星期二";
break;
case 3:
return "星期三";
break;
case 4:
return "星期四";
break;
case 5:
return "星期五";
break;
case 6:
return "星期六";
break;
}
}
}
})
</script>
</body>
</html>