RightClickMenu.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <template>
  2. <div class="right-click-menu">
  3. <div
  4. ref="RightMenuBody"
  5. class="right-menu-body"
  6. :style="styles"
  7. v-clickoutside="close"
  8. v-if="visible"
  9. >
  10. <ul>
  11. <li v-if="elementIsSelected" @click="toEdit">
  12. <i class="el-icon-edit-outline"></i> 编辑
  13. </li>
  14. <li v-if="elementIsSelected" class="li-danger" @click="toDelete">
  15. <i class="el-icon-delete"></i> 删除
  16. </li>
  17. <li v-if="elementIsSelected" @click="toCopy">
  18. <i class="el-icon-copy-document"></i> 复制
  19. </li>
  20. <li v-if="curCopyElement" @click="toPaste">
  21. <i class="el-icon-document-copy"></i> 粘贴
  22. </li>
  23. </ul>
  24. </div>
  25. </div>
  26. </template>
  27. <script>
  28. import { mapState, mapMutations, mapActions } from "vuex";
  29. import Clickoutside from "element-ui/src/utils/clickoutside";
  30. import { deepCopy, getElementId, randomCode } from "../../../plugins/utils";
  31. export default {
  32. name: "right-click-menu",
  33. directives: { Clickoutside },
  34. data() {
  35. return {
  36. visible: false,
  37. curColumnId: null,
  38. styles: {
  39. position: "fixed",
  40. zIndex: 3000,
  41. },
  42. rightClickPos: {},
  43. };
  44. },
  45. computed: {
  46. ...mapState("free", ["curElement", "curCopyElement"]),
  47. elementIsSelected() {
  48. return !!this.curElement.id;
  49. },
  50. },
  51. mounted() {
  52. this.init();
  53. },
  54. methods: {
  55. ...mapMutations("free", [
  56. "setOpenElementEditDialog",
  57. "setCurElement",
  58. "setCurCopyElement",
  59. ]),
  60. ...mapActions("free", ["actElementById", "removeElement", "pasteElement"]),
  61. init() {
  62. // 注册自定义右键事件菜单
  63. document.oncontextmenu = function () {
  64. return false;
  65. };
  66. document.addEventListener("mouseup", this.docMouseUp);
  67. },
  68. close() {
  69. this.visible = false;
  70. },
  71. show() {
  72. this.visible = true;
  73. },
  74. docMouseUp(e) {
  75. if (e.button === 2) {
  76. this.rightClick(e);
  77. }
  78. },
  79. rightClick(e) {
  80. const { elementId, columnId } = this.getRelateElementId(e.target);
  81. // 栏外的点击,不做任何处理
  82. if (!columnId) {
  83. this.curColumnId = null;
  84. this.setCurElement({});
  85. this.rightClickPos = {};
  86. return;
  87. }
  88. const { offsetLeft, offsetTop } = this.getOffsetInfo(
  89. e.target || e.srcElement
  90. );
  91. this.rightClickPos = {
  92. x: offsetLeft + e.offsetX,
  93. y: offsetTop + e.offsetY,
  94. };
  95. this.curColumnId = columnId;
  96. if (elementId) {
  97. this.actElementById(elementId);
  98. } else {
  99. this.setCurElement({});
  100. }
  101. // 既没有要黏贴的元素也没有选中的元素时,不显示右键菜单
  102. if (!this.curCopyElement.id && !this.curElement.id) return;
  103. this.show();
  104. this.$nextTick(() => {
  105. const { x: clickLeft, y: clickTop } = e;
  106. const { offsetWidth: menuWidth, offsetHeight: menuHeight } =
  107. this.$refs.RightMenuBody;
  108. const { innerWidth: wWidth, innerHeight: wHeight } = window;
  109. let menuLeft = clickLeft,
  110. menuTop = clickTop;
  111. if (menuWidth + clickLeft > wWidth) {
  112. menuLeft = clickLeft - menuWidth;
  113. }
  114. if (menuHeight + clickTop > wHeight) {
  115. menuTop = clickTop - menuHeight;
  116. }
  117. this.styles = Object.assign({}, this.styles, {
  118. top: menuTop + "px",
  119. left: menuLeft + "px",
  120. });
  121. });
  122. },
  123. getRelateElementId(dom) {
  124. let elementId = null,
  125. columnId = null;
  126. let parentNode = dom;
  127. while (!(columnId || parentNode.className.includes("page-box"))) {
  128. if (
  129. !elementId &&
  130. parentNode["id"] &&
  131. parentNode["id"].includes("element-")
  132. ) {
  133. elementId = parentNode["id"];
  134. }
  135. if (
  136. !columnId &&
  137. parentNode["id"] &&
  138. parentNode["id"].includes("column-")
  139. ) {
  140. columnId = parentNode["id"];
  141. }
  142. parentNode = parentNode.parentNode;
  143. }
  144. return { elementId, columnId };
  145. },
  146. getOffsetInfo(dom, endParentClass = "page-column-body") {
  147. let parentNode = dom;
  148. let offsetTop = 0,
  149. offsetLeft = 0;
  150. while (!parentNode.className.includes(endParentClass)) {
  151. offsetTop += parentNode.offsetTop;
  152. offsetLeft += parentNode.offsetLeft;
  153. parentNode = parentNode.offsetParent;
  154. }
  155. return {
  156. offsetLeft,
  157. offsetTop,
  158. };
  159. },
  160. toEdit() {
  161. this.close();
  162. this.setOpenElementEditDialog(true);
  163. },
  164. toDelete() {
  165. this.removeSelectElement();
  166. // this.close();
  167. // this.$confirm("确定要删除当前元素吗?", "提示", {
  168. // type: "warning"
  169. // })
  170. // .then(() => {
  171. // this.removeSelectElement();
  172. // })
  173. // .catch(() => {});
  174. },
  175. removeSelectElement() {
  176. this.close();
  177. this.removeElement(this.curElement);
  178. },
  179. toCopy() {
  180. this.close();
  181. this.setCurCopyElement(deepCopy(this.curElement));
  182. },
  183. toPaste() {
  184. this.close();
  185. this.pasteElement({
  186. element: {
  187. ...deepCopy(this.curCopyElement),
  188. ...this.rightClickPos,
  189. id: getElementId(),
  190. key: randomCode(),
  191. },
  192. toColumnId: this.curColumnId,
  193. });
  194. },
  195. },
  196. beforeDestroy() {
  197. document.oncontextmenu = null;
  198. document.removeEventListener("mouseup", this.docMouseUp);
  199. },
  200. };
  201. </script>