使用VUE组件建立SpreadJS自定义单元格(一)

2022年01月15日 阅读数:5
这篇文章主要向大家介绍使用VUE组件建立SpreadJS自定义单元格(一),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

做为近五年都冲在热门框架排行榜首的Vue,你们必定会学到的一部分就是组件的使用。前端开发的模块化,可让代码逻辑更加简单清晰,项目的扩展性大大增强。对于Vue而言,模块化的体现集中在组件之上,以组件为单位实现模块化。css

一般咱们使用组件的方式是,在实例化Vue对象以前,经过Vue.component方法来注册全局的组件。前端

// 告诉Vue,如今须要组件 todo-item,配置以下,包含props和template
Vue.component('todo-item', {
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
}) 
// 实例化一个Vue对象,挂载在#app-7元素下,定它的属性,数组groceryList 
var app7 = new Vue({
  el: '#app-7',
  data: {
    groceryList: [
      { text: 'Vegetables' },
      { text: 'Cheese' },
      { text: 'Whatever else humans are supposed to eat' }
    ]
  }
})

在众多组件之中,做为办公必备的电子表格,在前端组件中也占据了重要地位。除了以表格的形式展现数据,电子表格还有一个很是重要的功能,即支持自定义功能拓展和各类定制化的数据展现效果,好比checkbox,Radio button等;还须要实现当单元格进入编辑状态时,使用下拉菜单(或其余输入控件)输入的效果。咱们称之为"自定义单元格",一种嵌入组件内的组件。SpreadJS目前拥有8种下拉列表,在打开列表以前,咱们只须要在单元格样式中设置选项数据。 你能够参考如下代码使用列表:vue

在线体验地址element-ui

  // The way of click the dropdown icon to open list. 
   var style = new GC.Spread.Sheets.Style();
   style.cellButtons = [
       {
           imageType: GC.Spread.Sheets.ButtonImageType.dropdown,
           command: "openList",
           useButtonStyle: true,
       }
   ];
   style.dropDowns = [
       {
           type: GC.Spread.Sheets.DropDownType.list,
           option: {
               items: [
                   {
                       text: 'item1',
                       value: 'item1'
                   },
                   {
                       text: 'item2',
                       value: 'item2'
                   },
                   {
                       text: 'item3',
                       value: 'item3'
                   },
                   {
                       text: 'item4',
                       value: 'item4'
                   }
               ],
           }
       }
   ];
   sheet.setText(2, 1, "Vertical text list");
   sheet.setStyle(3, 1, style);

   // The way open list with command rather then clicking the dropdown button.
   spread.commandManager().execute({cmd:"openList",row:3,col:1,sheetName:"Sheet1"});


前端电子表格当然好用, 但因为框架生命周期以及自定义单元格渲染逻辑的问题,目前的技术手段没法直接在框架页面下直接经过template的方式使用框架下的组件。在以前的内容中,咱们提到了可使用Svelte使用Web Conmponents封装其余组件可使用的组件。
除了上面提到的方法以外,咱们若是想在Vue环境下使用自定义单元格,能够考虑使用持动态渲染的方式来建立和挂载组件,从而将组件注入自定义单元格。数组

下面为你们演演示如何在VUE项目中,建立一个使用VUE 组件的自定义单元格。app

实践

首先,在项目中开启运行时加载,在vue.config.js中添加runtimeCompiler: true。框架

    module.exports = {
        devServer: {
            port: 3000
        },
        <font color="#ff0000">runtimeCompiler: true</font>
      }


引用ElementUI,须要注意要把element 的css引用放在APP import前,这样修改样式,才能覆盖原有项目内容。模块化

import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'
import router from './router'

Vue.use(ElementUI);

new Vue({
  el: '#app',
  router,
  render: h => h(App)
})

Vue.config.productionTip = false


建立AutoComplateCellType,具体代码以下,须要注意几点。
一、自定义的元素,须要添加gcUIElement属性,若是元素或者其父元素没有该属性,点击建立的组件便会直接退出编辑状态没法编辑。
对于ElementUI 的autocomplete,默认下拉选项内容是注入到body中的,须要给组件模板中设置:popper-append-to-body="false",让弹出的下拉选项在gcUIElement的Div中渲染。
若是使用其余组件没有相似选项,也能够跟进实际状况在弹出时在添加gcUIElement属性。
二、使用动态挂载组件的 this.vm 设置和获取单元格的值。
三、在deactivateEditor中销毁组件。fetch

import Vue from 'vue'
import * as GC from "@grapecity/spread-sheets"
import DataService from './dataService'

function AutoComplateCellType() {
}
AutoComplateCellType.prototype = new GC.Spread.Sheets.CellTypes.Base();
AutoComplateCellType.prototype.createEditorElement = function (context, cellWrapperElement) {
  cellWrapperElement.style.overflow = 'visible'
  let editorContext = document.createElement("div")
  editorContext.setAttribute("gcUIElement", "gcEditingInput");
  let editor = document.createElement("div");
  // 自定义单元格中editorContext做为容器,须要在建立一个child用于挂载,不能直接挂载到editorContext上
  editorContext.appendChild(editor);
  return editorContext;
}
AutoComplateCellType.prototype.activateEditor = function (editorContext, cellStyle, cellRect, context) {
    let width = cellRect.width > 180 ? cellRect.width : 180;
    if (editorContext) {
        
        // 动态建立VUE 组件并挂载到editor
        const AutoCompleteComponent = {
            props: ['text','cellStyle'],
            template: `<div>
                        <el-autocomplete
                        :style="cellStyle"
                        popper-class="my-autocomplete"
                        v-model="text"
                        :fetch-suggestions="querySearch"
                        placeholder="请输入内容"
                        :popper-append-to-body="false"
                        value-key="name"
                        @select="handleSelect">
                        <i class="el-icon-edit el-input__icon"
                            slot="suffix"
                            @click="handleIconClick">
                        </i>
                        <template slot-scope="{ item }">
                            <div class="name">{{ item.name }}</div>
                            <span class="addr">{{ item.phone }}</span>
                        </template>
                        </el-autocomplete>
                    </div>`,
            mounted() {
                this.items = DataService.getEmployeesData();
            },
            methods: {
                querySearch(queryString, cb) {
                    var items = this.items;
                    var results = queryString ? items.filter(this.createFilter(queryString)) : items;
                    // 没法设置动态内容的位置,能够动态添加gcUIElement
                    // setTimeout(() => {
                    //   let popDiv = document.getElementsByClassName("my-autocomplete")[0];
                    //   if(popDiv){
                    //     popDiv.setAttribute("gcUIElement", "gcEditingInput");
                    //   }
                    // }, 500);
                    // 调用 callback 返回建议列表的数据
                    cb(results);
                },
                createFilter(queryString) {
                    return (restaurant) => {
                    return (restaurant.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
                    };
                },
                handleSelect(item) {
                    console.log(item);
                },
                handleIconClick(ev) {
                    console.log(ev);
                }
            }
        };

      // create component constructor
      const AutoCompleteCtor = Vue.extend(AutoCompleteComponent);
      this.vm = new AutoCompleteCtor({
        propsData: {
          cellStyle: {width: width+"px"}
        }
      }).$mount(editorContext.firstChild);
    }
    return editorContext;
};
AutoComplateCellType.prototype.updateEditor = function(editorContext, cellStyle, cellRect) {
    // 给定一个最小编辑区域大小
    let width = cellRect.width > 180 ? cellRect.width : 180;
    let height = cellRect.height > 40 ? cellRect.height : 40;
    return {width: width, height: height};
};
AutoComplateCellType.prototype.getEditorValue = function (editorContext) {
    // 设置组件默认值
    if (this.vm) {
        return this.vm.text;
    }
};
AutoComplateCellType.prototype.setEditorValue = function (editorContext, value) {
    // 获取组件编辑后的值
    if (editorContext) {
      this.vm.text = value;
    }
};
AutoComplateCellType.prototype.deactivateEditor = function (editorContext, context) {
    // 销毁组件
    this.vm.$destroy();
    this.vm = undefined;
};

export {AutoComplateCellType};


效果如图:ui

一个完美的单元格新鲜出炉~

这里介绍的方式只是诸多实现方案的一种。若是你们有其余更好的想法方法,欢迎一块儿讨论 ~

若是你对其余更多前端电子表格中有趣功能感兴趣,能够查看 SpreadJS更多实例演示

咱们也会在以后,持续为你们带来更多带来更多严肃和有趣的内容 ~