v-clickoutside.js 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import Vue from "vue";
  2. import { on } from "./dom";
  3. const nodeList = [];
  4. const ctx = "@@clickoutsideContext";
  5. let startClick;
  6. let seed = 0;
  7. !Vue.prototype.$isServer && on(document, "mousedown", e => (startClick = e));
  8. !Vue.prototype.$isServer &&
  9. on(document, "mouseup", e => {
  10. nodeList.forEach(node => node[ctx].documentHandler(e, startClick));
  11. });
  12. function createDocumentHandler(el, binding, vnode) {
  13. return function(mouseup = {}, mousedown = {}) {
  14. if (
  15. !vnode ||
  16. !vnode.context ||
  17. !mouseup.target ||
  18. !mousedown.target ||
  19. el.contains(mouseup.target) ||
  20. el.contains(mousedown.target) ||
  21. el === mouseup.target ||
  22. (vnode.context.popperElm &&
  23. (vnode.context.popperElm.contains(mouseup.target) ||
  24. vnode.context.popperElm.contains(mousedown.target)))
  25. )
  26. return;
  27. if (
  28. binding.expression &&
  29. el[ctx].methodName &&
  30. vnode.context[el[ctx].methodName]
  31. ) {
  32. vnode.context[el[ctx].methodName]();
  33. } else {
  34. el[ctx].bindingFn && el[ctx].bindingFn();
  35. }
  36. };
  37. }
  38. /**
  39. * v-clickoutside
  40. * @desc 点击元素外面才会触发的事件
  41. * @example
  42. * ```vue
  43. * <div v-element-clickoutside="handleClose">
  44. * ```
  45. */
  46. export default {
  47. bind(el, binding, vnode) {
  48. nodeList.push(el);
  49. const id = seed++;
  50. el[ctx] = {
  51. id,
  52. documentHandler: createDocumentHandler(el, binding, vnode),
  53. methodName: binding.expression,
  54. bindingFn: binding.value
  55. };
  56. },
  57. update(el, binding, vnode) {
  58. el[ctx].documentHandler = createDocumentHandler(el, binding, vnode);
  59. el[ctx].methodName = binding.expression;
  60. el[ctx].bindingFn = binding.value;
  61. },
  62. unbind(el) {
  63. let len = nodeList.length;
  64. for (let i = 0; i < len; i++) {
  65. if (nodeList[i][ctx].id === el[ctx].id) {
  66. nodeList.splice(i, 1);
  67. break;
  68. }
  69. }
  70. delete el[ctx];
  71. }
  72. };