RightClickMenu.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 {
  107. offsetWidth: menuWidth,
  108. offsetHeight: menuHeight
  109. } = this.$refs.RightMenuBody;
  110. const { innerWidth: wWidth, innerHeight: wHeight } = window;
  111. let menuLeft = clickLeft,
  112. menuTop = clickTop;
  113. if (menuWidth + clickLeft > wWidth) {
  114. menuLeft = clickLeft - menuWidth;
  115. }
  116. if (menuHeight + clickTop > wHeight) {
  117. menuTop = clickTop - menuHeight;
  118. }
  119. this.styles = Object.assign({}, this.styles, {
  120. top: menuTop + "px",
  121. left: menuLeft + "px"
  122. });
  123. });
  124. },
  125. getRelateElementId(dom) {
  126. let elementId = null,
  127. columnId = null;
  128. let parentNode = dom;
  129. while (!(columnId || parentNode.className.includes("page-box"))) {
  130. if (
  131. !elementId &&
  132. parentNode["id"] &&
  133. parentNode["id"].includes("element-")
  134. ) {
  135. elementId = parentNode["id"];
  136. }
  137. if (
  138. !columnId &&
  139. parentNode["id"] &&
  140. parentNode["id"].includes("column-")
  141. ) {
  142. columnId = parentNode["id"];
  143. }
  144. parentNode = parentNode.parentNode;
  145. }
  146. return { elementId, columnId };
  147. },
  148. getOffsetInfo(dom, endParentClass = "page-column-body") {
  149. let parentNode = dom;
  150. let offsetTop = 0,
  151. offsetLeft = 0;
  152. while (!parentNode.className.includes(endParentClass)) {
  153. offsetTop += parentNode.offsetTop;
  154. offsetLeft += parentNode.offsetLeft;
  155. parentNode = parentNode.offsetParent;
  156. }
  157. return {
  158. offsetLeft,
  159. offsetTop
  160. };
  161. },
  162. toEdit() {
  163. this.close();
  164. this.setOpenElementEditDialog(true);
  165. },
  166. toDelete() {
  167. this.removeSelectElement();
  168. // this.close();
  169. // this.$confirm("确定要删除当前元素吗?", "提示", {
  170. // type: "warning"
  171. // })
  172. // .then(() => {
  173. // this.removeSelectElement();
  174. // })
  175. // .catch(() => {});
  176. },
  177. removeSelectElement() {
  178. this.close();
  179. this.removeElement(this.curElement);
  180. },
  181. toCopy() {
  182. this.close();
  183. this.setCurCopyElement(deepCopy(this.curElement));
  184. },
  185. toPaste() {
  186. this.close();
  187. this.pasteElement({
  188. element: {
  189. ...deepCopy(this.curCopyElement),
  190. ...this.rightClickPos,
  191. id: getElementId(),
  192. key: randomCode()
  193. },
  194. toColumnId: this.curColumnId
  195. });
  196. }
  197. },
  198. beforeDestroy() {
  199. document.oncontextmenu = null;
  200. document.removeEventListener("mouseup", this.docMouseUp);
  201. }
  202. };
  203. </script>