【问题标题】:How to keep empty cells as empty in JSON output instead of ignore the cell (Vue-XLSX)如何在 JSON 输出中将空单元格保持为空而不是忽略单元格(Vue-XLSX)
【发布时间】:2021-10-04 04:02:07
【问题描述】:

我正在读取一个 Excel 文件,并在 Nuxt 项目中使用 vue-xlsx 将其转换为 JSON 对象。但是可能有空单元格。 Vue-xlsx 会忽略它们。

返回的 JSON 对象是这样的:

[ 
  { "Header1": "a", "Header3": "c" }, 
  { "Header1": "d", "Header2": "e", "Header3": "f" }, 
  { "Header1": "g", "Header2": "h", "Header3": "i" } 
]

我不需要使用“xlsx-table”组件打印它,因为我需要 JSON 对象。 试图以这种方式将defval 属性作为选项传递。但没有成功。

<section>
  <input type="file" @change="onChange" />
  <xlsx-read :options="options" :file="file">
    <xlsx-json :sheet="selectedSheet" >
      <template #default="{collection}">
        <!-- <xlsx-table :sheet="selectedSheet" /> -->
        <div>
          {{ json = collection }}
        </div>
      </template>
    </xlsx-json>
  </xlsx-read>
</section>

<script>
export default {
  data() {
    return {
      file: null,
      options: {
        defval: "",
      },
      json: null,
      selectedSheet: 0,
    };
  },
}
</script>

我需要一些帮助来生成这种 JSON 对象:

我如何使用 Vue-XLSX 做到这一点。

【问题讨论】:

    标签: json excel vue.js nuxt.js xlsx


    【解决方案1】:

    这可以用 VanillaJS 完成,不需要依赖 vue-xlxs 这个。

    如果我们确实从

    [ 
      { "Header1": "a", "Header3": "c" }, 
      { "Header1": "d", "Header2": "e", "Header3": "f" }, 
      { "Header1": "g", "Header2": "h", "Header3": "i" } 
    ]
    

    我们可以有以下

    <script>
    export default {
      data() {
        return {
          array: [
            { Header1: 'a', Header3: 'c' },
            { Header1: 'd', Header2: 'e', Header3: 'f' },
            { Header1: 'g', Header2: 'h', Header3: 'i' },
          ],
        }
      },
      mounted() {
        const neededHeaders = ['Header1', 'Header2', 'Header3']
        const arrayWithFallback = this.array.map((row) => {
          for (const headerKey of neededHeaders) {
            if (!(headerKey in row)) {
              // if you're missing one of the header, let's create a default value for it
              row[headerKey] = 'your-fallback-here' // can also be an empty string of course
            }
          }
          return row
        })
        console.log('arrayWithFallback', arrayWithFallback)
      },
    }
    </script>
    

    它会在最后创建这个

    [
      { "Header1": "a", "Header2": "your-fallback-here", "Header3": "c" },
      { "Header1": "d", "Header2": "e", "Header3": "f" },
      { "Header1": "g", "Header2": "h", "Header3": "i" }
    ]
    

    【讨论】:

    • 我无法在代码中硬编码标题。因为有时标题会随着文件的修改而改变。
    • @LahiruMadushan 然后,您可以使用数组中可用的最长对象进行快速搜索,获取它的键并将其用作标题(这种方式将是动态的)。
    • 但是如果有一个字段是所有记录都为空的,则流程将中断。是@kissu..?
    • 我们不能从 'vue-xlxs' 库中获取解决方案来考虑这些值吗?
    • @LahiruMadushan 我的意思是,如果仍然存在错误,您可以尝试并通过代码修复它,因为在一天结束时,您可以根据自己的喜好编辑数据。我已经发布了一个 github 问题,看看是否可以使用 defval,但我不确定是否可以:github.com/DonNicoJs/vue-xlsx/issues/19 随意订阅。
    【解决方案2】:

    我将documentation 中提到的“已解析”事件用于“xlsx-json”组件。这是我的完整 Nuxt 组件:

    如果你有“标题信息”:

    <template>
      <div>
        <h3>Import XLSX</h3>
        <input type="file" @change="onChange" />
        <xlsx-read :file="file">
          <xlsx-json @parsed = "parsFunc">
            <template #default="{collection}">
              <div class="divShow">
                {{ collection }}
              </div>
            </template>
          </xlsx-json>
        </xlsx-read>
      </div>
    </template>
    
    <script>
    /* put the address that matches for your app */
    import { XlsxRead, XlsxJson } from "~/node_modules/vue-xlsx/dist/vue-xlsx.es.js";
    
    export default {
      components: {
        XlsxRead,
        XlsxJson
      },
      data() {
        return {
          file: null,
          /* this array contains the exact words that you write on the first line of xlsx file */
          headerData: ["Header1", "Header2", "Header3"],
        };
      },
    
      computed: {
          lengData: function() {
              return this.headerData.length;
          } 
      }, 
    
      methods: {
        onChange(event) {
          this.file = event.target.files ? event.target.files[0] : null;
        },
    
        sortOutput(elemEach) {
            /* this function sorts the new object */
            let arrObj = Object.entries(elemEach);
            arrObj.sort((a,b) => a[0].localeCompare(b[0]));
            let arraySorted = Object.fromEntries(arrObj);
            return arraySorted; 
        },
    
        parsFunc(event) {
            /* this function loops throught elements in "xlsx" file and replaces empty cells with "" */
            let counter = 0;
            event.forEach(element => {
                for (let it = 0; it < this.lengData; it++) {
                    
                    if( element[this.headerData[it]] == undefined ) {
                        element[this.headerData[it]] = "";
                    }
                    
                }
    
                let sortedElem = this.sortOutput(element);
                
                event[counter] = sortedElem;
                
                counter++;
            }); // end of forEach
        
        }
      }
    };
    </script>
    
    <style scoped>
    /* this is the styles that I used */
    .divShow {
        background-color: #865611;
        padding: 50px;
        color: white;
    }
    </style>

    如果要动态生成“头信息”:

    <template>
      <div>
        <h3>Import XLSX</h3>
        <input type="file" @change="onChange" />
        <xlsx-read :file="file">
          <xlsx-json @parsed = "parsFunc">
            <template #default="{collection}">
              <div class="divShow">
                {{ collection }}
              </div>
            </template>
          </xlsx-json>
        </xlsx-read>
      </div>
    </template>
    
    <script>
    /* put the address that matches for your app */
    import { XlsxRead, XlsxJson } from "~/node_modules/vue-xlsx/dist/vue-xlsx.es.js";
    
    export default {
      components: {
        XlsxRead,
        XlsxJson
      },
      data() {
        return {
          file: null,
          headerData: [],
        };
      },
    
      computed: {
          lengData: function() {
              return this.headerData.length;
          } 
      }, 
    
      methods: {
        onChange(event) {
          this.file = event.target.files ? event.target.files[0] : null;
        },
    
        findHeader(elem, newArr) {
          /* this function finds the headers of the "xlsx" file */
          this.headerData = [];
          let convertArr = Object.entries(elem);
          convertArr.forEach(element2 => {
          newArr.push( Object.entries(element2[1]).length );
          });
    
          let indexOfMaxValue = newArr.reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);
          
          let arrayExtract =  Object.entries( convertArr[indexOfMaxValue][1] );
    
          arrayExtract.forEach(element3 => {
            this.headerData.push(element3[0]);
          });
    
          this.replaceEmpty(elem);
    
        },
    
        sortOutput(elemEach) {
            /* this function sorts the new object */
            let arrObj = Object.entries(elemEach);
            arrObj.sort((a,b) => a[0].localeCompare(b[0]));
            let arraySorted = Object.fromEntries(arrObj);
            return arraySorted; 
        },
    
        parsFunc(event) {
            /* this function acts after submitting file and call another function to find "headers" */
            let emptyArr = [];
            this.findHeader(event, emptyArr);
        },
    
        replaceEmpty: function(eventPass) {
          /* this function loops throught elements in "xlsx" file and replaces empty cells with "" */
          let counter = 0;
          eventPass.forEach(element => {
              
                for (let it = 0; it < this.lengData; it++) {
                    
                  if( element[this.headerData[it]] == undefined ) {
                          element[this.headerData[it]] = "";
                  }
                    
                }
    
                let sortedElem = this.sortOutput(element);
                
                eventPass[counter] = sortedElem;
                
                counter++;
            }); // end of forEach
    
        } // end of replaceEmpty
    
      }
    };
    </script>
    
    <style scoped>
    /* this is the styles that I used */
    .divShow {
        background-color: #865611;
        padding: 50px;
        color: white;
    }
    </style>

    但要使用此版本,您的 xlsx 文件中必须至少有 一个 完整的行。例如,此代码不适用于这种 xlsx 文件:

    【讨论】:

    • hamid-davodi 我无法在代码中硬编码标题。因为有时标题会随着文件的修改而改变。
    • 是的,我写的代码需要有“标题”信息。我将添加另一个不需要硬编码“标题”的代码。
    猜你喜欢
    • 2013-07-02
    • 2016-03-24
    • 1970-01-01
    • 2012-08-30
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多