RightClickMenu.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <template>
  2. <div class="right-click-menu">
  3. <el-popover
  4. placement="right-start"
  5. trigger="click"
  6. v-model="visible"
  7. popper-class="right-click-popper"
  8. :visible-arrow="false"
  9. >
  10. <div class="right-menu-body">
  11. <ul>
  12. <li @click="toEdit">编辑</li>
  13. <li @click="toDelete">删除</li>
  14. <li @click="toCopyChildren" v-if="IS_EXPLAIN_CHILDREN">
  15. 新增<br />答题区
  16. </li>
  17. <li
  18. @click="toDeleteChildren"
  19. v-if="IS_EXPLAIN_CHILDREN && showDeleteChildBtn"
  20. >
  21. 删除<br />答题区
  22. </li>
  23. </ul>
  24. </div>
  25. <el-button :style="styles" slot="reference"></el-button>
  26. </el-popover>
  27. </div>
  28. </template>
  29. <script>
  30. import { mapState, mapMutations, mapActions } from "vuex";
  31. import { fetchSameExplainNumberExplainChildernPositionInfo } from "../store";
  32. export default {
  33. name: "right-click-menu",
  34. data() {
  35. return {
  36. visible: false,
  37. showDeleteChildBtn: false,
  38. IS_EXPLAIN_CHILDREN: false,
  39. styles: {
  40. padding: "10px",
  41. position: "fixed",
  42. visibility: "hidden",
  43. zIndex: 3000
  44. }
  45. };
  46. },
  47. computed: {
  48. ...mapState("card", ["curElement", "pages"])
  49. },
  50. mounted() {
  51. this.init();
  52. },
  53. methods: {
  54. ...mapMutations("card", ["setOpenElementEditDialog"]),
  55. ...mapActions("card", [
  56. "actElementById",
  57. "removeElement",
  58. "removeElementChild",
  59. "rebuildPages",
  60. "copyExplainChildren",
  61. "deleteExplainChildren"
  62. ]),
  63. init() {
  64. // 注册自定义右键事件菜单
  65. document.oncontextmenu = function() {
  66. return false;
  67. };
  68. document.addEventListener("mouseup", e => {
  69. if (e.button === 2) {
  70. this.visible = false;
  71. this.rightClick(e);
  72. }
  73. });
  74. },
  75. rightClick(e) {
  76. const id = this.getRelateElementId(e.target);
  77. if (!id) return;
  78. this.actElementById(id);
  79. this.styles = Object.assign({}, this.styles, {
  80. top: e.y + "px",
  81. left: e.x - 50 + "px"
  82. });
  83. const positionInfos = fetchSameExplainNumberExplainChildernPositionInfo(
  84. this.curElement,
  85. this.pages
  86. );
  87. this.showDeleteChildBtn = positionInfos.length >= 2;
  88. this.IS_EXPLAIN_CHILDREN = this.curElement.type === "EXPLAIN_CHILDREN";
  89. // 直接用了setTimeout,解决弹出框跟随延迟的问题,似乎粗暴了点。
  90. setTimeout(() => {
  91. this.visible = true;
  92. }, 100);
  93. // this.$nextTick(() => {
  94. // });
  95. },
  96. getRelateElementId(dom) {
  97. let parentNode = dom;
  98. while (
  99. !(
  100. (parentNode["id"] && parentNode["id"].includes("element-")) ||
  101. parentNode.className.includes("page-column-body")
  102. )
  103. ) {
  104. parentNode = parentNode.parentNode;
  105. }
  106. const elementType = parentNode.getAttribute("data-type");
  107. const unValidElement = ["TOPIC_HEAD", "CARD_HEAD"];
  108. return parentNode["id"] &&
  109. elementType &&
  110. !unValidElement.includes(elementType)
  111. ? parentNode["id"]
  112. : null;
  113. },
  114. toEdit() {
  115. this.visible = false;
  116. this.setOpenElementEditDialog(true);
  117. },
  118. toDelete() {
  119. this.visible = false;
  120. this.$confirm("确定要删除当前元素吗?", "提示", {
  121. cancelButtonClass: "el-button--danger is-plain",
  122. confirmButtonClass: "el-button--primary",
  123. type: "warning"
  124. })
  125. .then(() => {
  126. this.removeSelectElement();
  127. })
  128. .catch(() => {});
  129. },
  130. toCopyChildren() {
  131. this.visible = false;
  132. this.copyExplainChildren(this.curElement);
  133. this.$nextTick(() => {
  134. this.rebuildPages();
  135. });
  136. },
  137. toDeleteChildren() {
  138. // TODO:校验当前元件是否可以删除
  139. this.visible = false;
  140. this.deleteExplainChildren(this.curElement);
  141. this.$nextTick(() => {
  142. this.rebuildPages();
  143. });
  144. },
  145. removeSelectElement() {
  146. if (this.curElement["container"]) {
  147. this.removeElementChild(this.curElement);
  148. } else {
  149. this.removeElement(this.curElement);
  150. }
  151. // 作文题是个坑爹的设计,删除子元件之后会影响主体题卡布局,解答题小题不会
  152. if (
  153. !this.curElement["container"] ||
  154. this.curElement["container"].type === "COMPOSITION"
  155. )
  156. this.$nextTick(() => {
  157. this.rebuildPages();
  158. });
  159. }
  160. }
  161. };
  162. </script>