vue自定义页面

需求:拖拉拽形成页面
效果:可定义客户端和移动端基本样式:栅格,宽高,阴影等,且客户端与移动端样式互不影响,这里只有大体样式,并不是最终展示效果
附图:


image.png

逻辑就不多说了,就是拖拽

<template>
  <div>
    <div class="custom_box">
      <div class="left">
        <div class="title_box">
          组件库
        </div>
        <div class="main_box">
          <ul class="left_ul">
            <li
              v-for="(item, index) in leftList"
              :id="item.type"
              :key="item.iden"
              class="left_li"
              draggable="true"
              @dragstart="leftDrag($event, index)"
            >
              {{ item.name }}
            </li>
          </ul>
        </div>
      </div>
      <div
        class="center"
        @drop="contentDrop($event)"
        @dragover="contentDragover($event)"
      >
        <div class="title_box">
          <div>
            <a-form layout="inline" :label-col="{ span: 5 }">
              <a-form-item label="展示端">
                <a-select v-model="terminal">
                  <a-select-option value="pcInfo">
                    PC端
                  </a-select-option>
                  <a-select-option value="mobileInfo">
                    移动端
                  </a-select-option>
                </a-select>
              </a-form-item>
            </a-form>
          </div>
          <div>
            <a-button type="primary" @click="watchFn('pcInfo')">
              预览PC
            </a-button>
            <a-button type="primary" @click="watchFn('mobileInfo')">
              预览Mobile
            </a-button>
          </div>
        </div>
        <div class="content main_box">
          <div
            v-for="(view, index) in info"
            :key="view.iden"
            class="content_item"
            draggable="true"
            @dragenter="enter($event, view)"
            @dragstart="handleDragStart($event, view)"
            @dragover.prevent="handleDragover($event)"
          >
            <component
              :is="view.type"
              :is-disabled="true"
              :terminal="terminal"
              :view-info="info[index]"
            />
            <div
              class="mask_box"
              :class="view.iden === notContentIden ? 'active' : ''"
              @click="editData(view, index)"
            >
              <a-icon
                class="icon_del"
                type="delete"
                @click="deleteFn(view, index)"
              />
            </div>
          </div>
        </div>
      </div>
      <div class="right">
        <div class="title_box">
          组件属性
        </div>
        <div class="main_box">
          <div class="right_main">
            <WriteChildren
              v-for="(child, index) in rightList"
              :key="index"
              :edit-info.sync="editInfo"
              :terminal="terminal"
              :index="index"
            />
          </div>
        </div>
      </div>
    </div>
    <div class="dialog">
      <a-drawer
        title="预览"
        :visible="visibleModal"
        width="100%"
        @close="onClose"
      >
        <div
          class="main"
          :style="{ width: watchType == 'pcInfo' ? '' : '375px' }"
        >
          <div
            v-for="(view, index) in info"
            :key="index"
            :style="[
              {
                width:
                  view.type != 'JrBanner' && watchType == 'pcInfo'
                    ? '1200px'
                    : '100%',
              },
              { margin: 'auto' },
            ]"
          >
            <component
              :is="view.type"
              :terminal="watchType"
              :usage-scenarios="true"
              :view-info="info[index]"
            />
          </div>
        </div>
      </a-drawer>
    </div>
  </div>
</template>

<script>
import { debounce } from "@/libs/utils";
// 编写
import WriteChildren from "./writeChildren/index";
// 视图
import JrBanner from "./viewChildren/jrBanner";
import JrCard from "./viewChildren/jrCard";
import JrAdvert from "./viewChildren/jrAdvert";
export default {
  name: "Custom",
  components: {
    // 编写
    WriteChildren,
    // 视图
    JrBanner,
    JrCard,
    JrAdvert,
  },
  data() {
    return {
      data: [],
      contentList: [],
      leftList: [
        {
          iden: 1,
          type: "JrBanner",
          name: "轮播",
          field_name: "banner",
        },
        {
          iden: 2,
          type: "JrCard",
          name: "卡片",
        },
        {
          iden: 20,
          type: "JrAdvert",
          name: "广告",
        },
      ],
      editInfo: {},
      info: [],
      rightList: [],
      terminal: "pcInfo",
      checkInfo: {},
      notContentIden: null,
      visibleModal: false,
      watchType: "pcInfo",
    };
  },
  computed: {
    formInfo() {
      let arr = [];
      this.info.map((item) => {
        arr.push({
          title: item.name,
          dataIndex: item.field_name,
        });
      });
      return arr;
    },
    itemId() {
      return this.$route.query.id;
    },
  },
  created() {
    this.enter = debounce(this.handleDragEnter, 300);
  },
  methods: {
    leftDrag(ev) {
      ev.dataTransfer.setData("Text", ev.target.id);
    },
    //添加
    contentDrop(ev) {
      if (this.type) {
        this.type = false;
        return false;
      }
      ev.preventDefault();
      let newLeftList = JSON.parse(JSON.stringify(this.leftList));
      var index = newLeftList.findIndex((item) => {
        return item.type === ev.dataTransfer.getData("Text");
      });
      let data = newLeftList[index];
      data.iden = new Date().getTime();
      data.show_title = false;
      data.fatherCode = ""; // 广告位code
      data.pcInfo = {
        height: 300,
        count: 3,
        bgColor: "",
        shadow: true,
        alignment: "left",
      };
      data.mobileInfo = {
        height: 300,
        count: 2,
        bgColor: "",
        shadow: true,
        alignment: "center",
      };
      this.notContentIden = data.iden;
      data.options = [
        // value:值,key:键,main_text:主文本,sub_text:副文本,topNumber:距离顶部距离
        { value: "", key: "", main_text: "", sub_text: "", topNumber: 0 },
      ];
      this.editInfo = data;
      this.rightList = [];
      this.info.push(data);
      this.rightList.push(data);
    },
    contentDragover(ev) {
      ev.preventDefault();
    },
    //编辑/修改
    editData(data) {
      this.notContentIden = data.iden;
      this.rightList = [];
      this.rightList.push(data);
      this.editInfo = data;
    },

    /* 换位 */
    handleDragStart(ev, data) {
      this.type = true;
      this.checkInfo = data;
    },
    handleDragover(ev) {
      ev.dataTransfer.dropEffect = "move";
      ev.preventDefault();
    },
    handleDragEnter(ev, data) {
      ev.dataTransfer.effectAllowed = "move";
      if (data === this.checkInfo) {
        return false;
      }
      const newData = [...this.info];
      const src = newData.indexOf(this.checkInfo);
      const dst = newData.indexOf(data);
      newData.splice(dst, 0, ...newData.splice(src, 1));
      this.info = newData;
    },
    //删除
    deleteFn(data, index) {
      this.info.splice(index, 1);
    },
    //查看/预览
    watchFn(type) {
      this.watchType = type;
      this.visibleModal = true;
    },
    onClose() {
      this.visibleModal = false;
    },
  },
};
</script>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容