本帖最后由 dexteryao 于 2021-9-23 10:49 编辑
SpreadJS自定义单元格功能提供了强大的拓展能力,一方面拓展数据展示的效果,比如checkbox,Radio button的形式展示数据。另一方面,当单元格进入编辑状态可以使用下拉菜单等任何输入控件来进行输入。
关于自定义单元格的内容可以参考学习指南-自定义单元格以及API文档。
由于框架生命周期以及自定义单元格渲染逻辑的问题,目前无法直接在框架页面下直接通过template的方式使用框架下的组件。
经过了一些调研,VUE支持动态渲染的方式来创建和挂载组件,考虑可以通过这种方式在自定义单元格中注入组件。
下面使用Element UI中autocomplete为例,演示如何在VUE 2 的项目中给SpreadJS创建一个使用VUE 组件的自定义单元格。
这种方式是否有副作用还不清楚,使用时请详细测试,大家也可以跟帖讨论,一起完善方案。
Demo中数据时mock的,实际使用中可以参考combo celltype 通过items传入。
首先,需要在项目中开启运行时加载,在vue.config.js中添加runtimeCompiler: true(更新:可以参考https://gcdn.grapecity.com.cn/showtopic-131931-1-1.html 不设置此选项)
- 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,具体代码如下,需要注意几点。
1. 对于自定义的元素,需要添加gcUIElement属性,如果元素或者其父元素没有该属性,点击创建的组件便会直接退出编辑状态无法编辑。
对于ElementUI 的autocomplete,默认下拉选项内容是注入到body中的,这就导致上面说问题,这里需要给组件模板中设置:popper-append-to-body="false",让弹出的下拉选项在gcUIElement的Div中渲染。
如果使用其他组件没有类似选项,也可以跟进实际情况在弹出时在添加gcUIElement属性。
2. 使用动态挂载组件的 this.vm 设置和获取 单元格的值。
3. 在deactivateEditor中销毁组件
- 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};
复制代码
最后,按照一般使用单元格类型的方式设置即可
- import {AutoComplateCellType} from "../static/autocomplateCellType"
复制代码- var sheet = spread.getActiveSheet();
- sheet.getCell(1, 1).value("A").backColor("lightblue")
- sheet.setCellType(1, 1, new AutoComplateCellType())
复制代码
效果如图:
|
|