1024倾情巨献Vue3+element-plus(非脚手架纯html!!!)开发可拖拽表格以及列的动态显示隐藏

149 阅读3分钟

引入Vue3以及element-plus

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- Import style -->
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/element-plus/dist/index.css" />

</head>

<body>
    <div id="app">
        <el-button>{{ nMessage }}</el-button>
    </div>
    <!-- Import Vue 3 -->
    <script src="//cdn.jsdelivr.net/npm/vue@3"></script>
    <!-- Import component library -->
    <script src="//cdn.jsdelivr.net/npm/element-plus"></script>
    <script>
         const { createApp, ref } = Vue
        const App = {
            setup(){
                const nMessage=ref('Hello World!')

                return{
                    nMessage
                }
            },
            //or
            data() {
                return {
                    message: "Hello Element Plus",
                };
            },
        };
        const app = Vue.createApp(App);
        app.use(ElementPlus);
        app.mount("#app");
    </script>
</body>

</html>

引入官网el-table的基础示例代码你会发现el-table-columnwidth设置并没有生效,下面是解决的方法,说来也奇怪,将el-table-column改成v-for循环展示...哎 你会发现它就正常了

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- Import style -->
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/element-plus/dist/index.css" />

</head>

<body>
    <div id="app">
        <el-table :data="tableData" border style="width: 100%" fixed>
            <template v-for="(item,index) in columnList" :key="index">
                <el-table-column :type="item.type" :prop="item.prop" :label="item.label" :width="item.width" :key="item.prop" v-if="item.visible" />
            </template>
        </el-table>
    </div>
    <!-- Import Vue 3 -->
    <script src="//cdn.jsdelivr.net/npm/vue@3"></script>
    <!-- Import component library -->
    <script src="//cdn.jsdelivr.net/npm/element-plus"></script>
    <script>
         const { createApp, ref } = Vue
        const App = {
            setup(){
                const columnList = ref([
                    { type: 'selection', width: 55, visible: true },
                    { type: 'index', width: 55, visible: true },
                    { label: '名称', prop: 'name', input: '', visible: true, width: 180 },
                    { label: '类型', prop: 'type', input: '', visible: true, width: 180 },
                    { label: '价格', prop: 'price', input: '', visible: true, width: null },

                ]);

                const tableData = ref([
                    { id: 1, name: '纸巾', type: '百货', price: 30 },
                    { id: 2, name: '抽纸', type: '百货', price: 18 },
                    { id: 3, name: '水杯', type: '百货', price: 50 },

                ]);

                return{
                    columnList,
                    tableData
                }
            },
            //or
            data() {
                return {
                    message: "Hello Element Plus",
                };
            },
        };
        const app = Vue.createApp(App);
        app.use(ElementPlus);
        app.mount("#app");
    </script>
</body>

</html>

接下来是动态控制显示隐藏列,我们在表格上面添加一个设置的icon

问题又来了,icon不显示

查看官网使用说明发现需要引入<script src="//cdn.jsdelivr.net/npm/@element-plus/icons-vue"></script>并注册所有的icon组件才能政策显示

const app = Vue.createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
}
app.use(ElementPlus);
app.mount("#app");

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- Import style -->
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/element-plus/dist/index.css" />
    <style>
        .el-popover.el-popper {
            min-width: 0 !important;
        }
    </style>
</head>

<body>
    <div id="app">
        <div style="display: flex;justify-content: flex-end;margin-bottom: 5px;margin-right: 5px;cursor: pointer;">
            <el-popover placement="bottom" :width="100" trigger="click">
                <template #reference>
                    <el-icon>
                        <Setting />
                    </el-icon>
                </template>
                <div>
                    <div v-for="(item,index) in labelSwitchList" :key="index"><span
                            style="margin-right: 5px;">{{item.label}}</span><el-switch v-model="item.visible" />
                    </div>
                </div>
            </el-popover>

        </div>
        <el-table :data="tableData" border style="width: 100%" fixed>
            <template v-for="(item,index) in columnList" :key="index">
                <el-table-column :type="item.type" :prop="item.prop" :label="item.label" :width="item.width" :key="item.prop" v-if="item.visible" />
            </template>
        </el-table>
    </div>
    <!-- Import Vue 3 -->
    <script src="//cdn.jsdelivr.net/npm/vue@3"></script>
    <!-- Import component library -->
    <script src="//cdn.jsdelivr.net/npm/element-plus"></script>
    <script src="//cdn.jsdelivr.net/npm/@element-plus/icons-vue"></script>
    <script>
         const { createApp, ref,computed } = Vue
        const App = {
            setup(){
                const columnList = ref([
                    { type: 'selection', label:'选择',width: 55, visible: true },
                    { type: 'index',  label:'索引',width: 55, visible: true },
                    { label: '名称', prop: 'name', input: '', visible: true, width: 180 },
                    { label: '类型', prop: 'type', input: '', visible: true, width: 180 },
                    { label: '价格', prop: 'price', input: '', visible: true, width: null },

                ]);

                const tableData = ref([
                    { id: 1, name: '纸巾', type: '百货', price: 30 },
                    { id: 2, name: '抽纸', type: '百货', price: 18 },
                    { id: 3, name: '水杯', type: '百货', price: 50 },

                ]);
                const labelSwitchList = computed(() => {
                    return columnList.value
                })

                return{
                    columnList,
                    tableData,
                    labelSwitchList
                }
            },
            //or
            data() {
                return {
                    message: "Hello Element Plus",
                };
            },
        };
        const app = Vue.createApp(App);
        for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
            app.component(key, component)
        }
        app.use(ElementPlus);
        app.mount("#app");
    </script>
</body>

</html>

最后进行列拖拽功能的开发,需要引入插件Sortable

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- Import style -->
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/element-plus/dist/index.css" />
    <style>
        .el-popover.el-popper {
            min-width: 0 !important;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="dragbox">
            <div style="display: flex;justify-content: flex-end;margin-bottom: 5px;margin-right: 5px;cursor: pointer;">
                <el-popover placement="bottom" :width="100" trigger="click">
                    <template #reference>
                        <el-icon>
                            <Setting />
                        </el-icon>
                    </template>
                    <div>
                        <div v-for="(item,index) in labelSwitchList" :key="index"><span
                                style="margin-right: 5px;">{{item.label}}</span><el-switch v-model="item.visible" />
                        </div>
                    </div>
                </el-popover>

            </div>
            <el-table :data="tableData" border style="width: 100%" fixed>
                <template v-for="(item,index) in columnList" :key="index">
                    <el-table-column :type="item.type" :prop="item.prop" :label="item.label" :width="item.width"
                        :class-name="index>1 ? 'allow-drag' : ' '" :key="item.prop" v-if="item.visible" />
                </template>
            </el-table>
        </div>

    </div>
    <!-- Import Vue 3 -->
    <script src="//cdn.jsdelivr.net/npm/vue@3"></script>
    <!-- Import component library -->
    <script src="//cdn.jsdelivr.net/npm/element-plus"></script>
    <script src="//cdn.jsdelivr.net/npm/@element-plus/icons-vue"></script>
    <script src="//cdn.jsdelivr.net/npm/sortablejs@1.10.2/Sortable.min.js"></script>
    <script>
        const { createApp, ref, computed, onMounted } = Vue
        const App = {
            setup() {
                const columnList = ref([
                    { type: 'selection', label: '选择', width: 55, visible: true },
                    { type: 'index', label: '索引', width: 55, visible: true },
                    { label: '名称', prop: 'name', input: '', visible: true, width: 180 },
                    { label: '类型', prop: 'type', input: '', visible: true, width: 180 },
                    { label: '价格', prop: 'price', input: '', visible: true, width: null },

                ]);

                const tableData = ref([
                    { id: 1, name: '纸巾', type: '百货', price: 30 },
                    { id: 2, name: '抽纸', type: '百货', price: 18 },
                    { id: 3, name: '水杯', type: '百货', price: 50 },

                ]);
                const labelSwitchList = computed(() => {
                    return columnList.value
                })
                const columnDrop = () => {
                    const tr = document.querySelector('.dragbox .el-table__header-wrapper tr');
                    console.log(tr);
                    Sortable.create(tr, {
                        animation: 150,
                        delay: 0,
                        //draggable可拖动的列,不设置的列不能拖动,也不能作为可以拖动的列的落点
                        draggable: '.allow-drag',
                        //可以换位置但不能拖动设置--filter
                        // filter:'.el-table_1_column_1,.el-table_1_column_2',
                        onEnd: (evt) => {
                            if (evt.newIndex < 2) return false
                            const oldItem = columnList.value[evt.oldIndex];
                            columnList.value.splice(evt.oldIndex, 1);
                            columnList.value.splice(evt.newIndex, 0, oldItem);
                        }
                    });

                }
                onMounted(() => {
                    columnDrop()
                })
                return {
                    columnList,
                    tableData,
                    labelSwitchList
                }
            },
            //or
            data() {
                return {
                    message: "Hello Element Plus",
                };
            },
        };
        const app = Vue.createApp(App);
        for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
            app.component(key, component)
        }
        app.use(ElementPlus);
        app.mount("#app");
    </script>
</body>

</html>

最后分享一下在html文件中引入.vue文件的组件

需要引入vue3-sfc-loader.js

<body>
...
<!-- Import Vue 3 --> <script src="//cdn.jsdelivr.net/npm/vue@3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue3-sfc-loader/dist/vue3-sfc-loader.js"></script>
<script>
const options = {
            moduleCache: {
                vue: Vue
            },
            async getFile(url) {

                const res = await fetch(url);
                if (!res.ok)
                    throw Object.assign(new Error(res.statusText + ' ' + url), { res });
                return {
                    getContentData: asBinary => asBinary ? res.arrayBuffer() : res.text(),
                }
            },
            addStyle(textContent) {

                const style = Object.assign(document.createElement('style'), { textContent });
                const ref = document.head.getElementsByTagName('style')[0] || null;
                document.head.insertBefore(style, ref);
            },
        }

        const { loadModule } = window['vue3-sfc-loader'];
        const App={
          ...
          //在此处注册组件
          components: {
                'my-component': defineAsyncComponent(() => loadModule('./myComponent.vue', options))
            }
        }
        const app = Vue.createApp(App);
        for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
            app.component(key, component)
        }
        //或者在此处注册组件(二选一即可)
        app.component('my-component',defineAsyncComponent
        (() => loadModule('./myComponent.vue', options)))
        app.use(ElementPlus);
        app.mount("#app");
</script>
</body>