在线打印
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

174 lines
3.9 KiB

  1. <template>
  2. <div id="viewport" data-type="viewport" class="holder">
  3. <div
  4. :style="{
  5. height: page.height + 'px',
  6. width: page.width + 'px',
  7. backgroundImage: 'url('+backImg+')'
  8. }"
  9. class="screen"
  10. >
  11. <!-- 组件 -->
  12. <component
  13. v-for="val in widgetStore"
  14. :is="val.type"
  15. :data-title="val.type"
  16. :class="{'active': widgetId === val.uuid}"
  17. :key="val.uuid"
  18. :val="val"
  19. :data-type="val.type"
  20. :data-uuid="val.uuid"
  21. class="layer"
  22. ></component>
  23. <!-- 参考线 -->
  24. <!-- <ref /> -->
  25. <!-- 尺寸控制器 -->
  26. <control />
  27. </div>
  28. </div>
  29. </template>
  30. <script>
  31. import control from './size-control.vue'
  32. import move from '../../mixins/move'
  33. export default {
  34. components: {
  35. control, // 尺寸控制
  36. },
  37. mixins: [move],
  38. data() {
  39. return {}
  40. },
  41. computed: {
  42. // 已添加的组件
  43. widgetStore() {
  44. return this.$vptd.state.page.tempItems
  45. },
  46. // 背景图地址
  47. backImg() {
  48. return this.$vptd.state.page.imageUrl ? this.$vptd.state.page.imageUrl : ''
  49. },
  50. // 画布高度
  51. page() {
  52. return this.$vptd.state.page
  53. },
  54. // 选中项id
  55. widgetId() {
  56. return this.$vptd.state.uuid
  57. },
  58. },
  59. mounted() {
  60. // 采用事件代理的方式监听元件的选中操作
  61. let viewportDom = document.getElementById('viewport')
  62. if (viewportDom) {
  63. viewportDom.addEventListener('mousedown', this.handleSelection, false)
  64. } else {
  65. console.error('未找的‘viewport’节点')
  66. }
  67. // 绑定键盘上下左右键用于元件的移动
  68. document.addEventListener(
  69. 'keydown',
  70. (e) => {
  71. e.stopPropagation()
  72. var target = this.$vptd.state.activeElement
  73. // 左
  74. if (e.keyCode === 37 && target.left) {
  75. target.left -= 1
  76. return
  77. }
  78. // 上
  79. if (e.keyCode === 38 && target.top) {
  80. e.preventDefault()
  81. target.top -= 1
  82. return
  83. }
  84. // 右
  85. if (e.keyCode === 39 && target.left) {
  86. target.left += 1
  87. return
  88. }
  89. // 下
  90. if (e.keyCode === 40 && target.top) {
  91. e.preventDefault()
  92. target.top += 1
  93. }
  94. },
  95. true
  96. )
  97. },
  98. methods: {
  99. /**
  100. * 目标元素获得焦点
  101. */
  102. handleSelection(e) {
  103. var target = this.selectTarget(e.target)
  104. if (target) {
  105. var uuid = target.getAttribute('data-uuid')
  106. // 设置选中元素
  107. this.$vptd.commit('select', {
  108. uuid: uuid || -1,
  109. })
  110. // 绑定移动事件:除背景图以外的元件才能移动
  111. target = this.$vptd.state.activeElement
  112. if (target.dragable) {
  113. this.initmovement(e) // 参见 mixins
  114. }
  115. } else {
  116. // 取消选中元素
  117. this.$vptd.commit('select', {
  118. uuid: -1,
  119. })
  120. }
  121. },
  122. /**
  123. * 获得选中的目标,如果没有返回false
  124. */
  125. selectTarget(target) {
  126. let type = target.getAttribute('data-type')
  127. if (type) {
  128. if (type === 'viewport') {
  129. return false
  130. } else {
  131. return target
  132. }
  133. } else {
  134. return this.selectTarget(target.parentNode)
  135. }
  136. },
  137. },
  138. }
  139. </script>
  140. <style scoped>
  141. .holder {
  142. display: flex;
  143. justify-content: center;
  144. overflow: auto;
  145. font-size: 0;
  146. border: 1px solid #f5f5f5;
  147. border-width: 0 1px;
  148. background-image: linear-gradient(45deg, #f5f5f5 25%, transparent 0, transparent 75%, #f5f5f5 0),
  149. linear-gradient(45deg, #f5f5f5 25%, transparent 0, transparent 75%, #f5f5f5 0);
  150. background-position: 0 0, 13px 13px;
  151. background-size: 26px 26px;
  152. }
  153. .screen {
  154. margin: 25px auto;
  155. transform-origin: center top;
  156. position: relative;
  157. box-shadow: 0 0 5px 1px #cccccc;
  158. background-color: #ffffff;
  159. background-repeat: no-repeat;
  160. }
  161. </style>