Vue3实现拖拽定制化首页

大家好,我是王大傻.最近呢,写了一个定制化拖拽首页的功能,借此来讲一下心得.

前期准备

    Vue3 Ts VueDragable (4版本以上) 期望 拖拽组件 组件可以按需加载导入

开始

首先呢,我们先看下VueDragable的文档效果

文档的效果是这种基于列表的一个拖拽排序,那么回归到我们期望我们是想通过动态引入组件来进行拖拽排序,那么在完成拖拽定制化之前,首先要讲的是动态组件,在使用Vue2时候相信我们不陌生我们可以通过Component is来动态引入,如:

<template>
  <div class="component-box">
     <component :is="xxx""/>          
  </div>
</template>
<script> import xxx from xxx.vue
export default{
    data(){
        return{

        }
    },
    components:{
        xxx
    }
} </script>

其中is的值就是我们在components中注册的组件,这样就能完成动态组件的注入,那么在Vue3中呢?尤其是在setup语法糖使用时候我们这样做就会导致无法识别组件,这是因为setup语法糖中我们可以直接引入组件后使用,并不需要通过在components中注册(默认帮我们完成了),那么我们真实的业务场景其实后台返给我们的数据是这个格式的:

因此,我们的动态组件也需要做调整:

<div class="component-box" v-for="element in xxx">
  <component :is="element.name" :key="element.name"/>
</div>

这时候我们的is绑定就并非一个组件的实例了,其实是一个字符串,如此一来,就会产生错误并且导致页面无法正常加载我们的组件,那么该怎么办呢?大傻在网上做了调研,有三种方法:

方法一

通过Vue3的defineAsyncComponent方法去完成动态加载组件,使其成为一个实例对象。

import { defineAsyncComponent, ref } from vue

// 需要加载的组件集合
const components = ref(new Map<string, any>())
components.value.set(
  test1,
  defineAsyncComponent(() => import(./test1.vue))
)
components.value.set(
  test2,
  defineAsyncComponent(() => import(./test2.vue))
)

这样我们在取值时候可以通过get方法传入具体字符串拿到对应的组件

方法二

这个则是通过shallowRef 或者 markRaw 来进行代理,shallowRef是浅层代理,只去代理一层,而markRaw则是标记该属性永远不为响应式

import { shallowRef, ref } from vue
  import test1 from ./test1.vue
  import test2 from ./test2.vue
 
  //这里用ref的话,vue给出警告Vue接收到一个组件,该组件被制成响应对象。这可能会导致不必要的性能开销,应该通过将组件标记为“markRaw”或使用“shallowRef”而不是“ref”来避免。
  
  // 如果使用 markRaw 那么currentComp将不永远不会再成为响应式对象。 所以得使用 shallowRef
  let currentComp = shallowRef(test1)  
 currentComp.value
  // 切换组件
  const changeComp = () => {
    if(currentComp.value == test1) {
      currentComp.value = test2
    }else {
      currentComp.value = test1
    }
  }

这种方法可行,但是不能传入字符串进行动态引入

方案三

双script标签完美解决

<script lang="ts"> import {
  Test1,
  Test2,
} from ./components/DragComponents

export default {
  components: {
    Test1,
    Test2,
  }
} </script>
<script setup lang="ts"> const componentList = reactive([
  {
    name: Test1,
    title: 测试1,
    id: 1
  },
  {
    name: Test2,
    title: 测试2,
    id: 2
  }
]) </script>

这样我们可以直接去拿到后台数据进行处理。

最终实现结果

大傻最终呢,也是通过不断地爬坑去实现了这个拖拽效果,目前完成了横纵方向两种布局,待拓展的也就是,可定制宽高等等这些内容。有兴趣可以留言,大家一起交流。

经验分享 程序员 微信小程序 职场和发展