forked from sheetjs/docs.sheetjs.com
		
	vue
This commit is contained in:
		
							parent
							
								
									d4a38231dd
								
							
						
					
					
						commit
						2d5f8ebce4
					
				| @ -27,6 +27,86 @@ suitable for a number of libraries.  When more advanced shapes are needed, | ||||
| it is easier to munge the output of an array of arrays. | ||||
| 
 | ||||
| 
 | ||||
| ### x-spreadsheet | ||||
| 
 | ||||
| With a familiar UI, [`x-spreadsheet`](https://myliang.github.io/x-spreadsheet/) | ||||
| is an excellent choice for developers looking for a modern editor. | ||||
| 
 | ||||
| [Click here for a live integration demo.](pathname:///xspreadsheet/) | ||||
| 
 | ||||
| <details><summary><b>Full Exposition</b> (click to show)</summary> | ||||
| 
 | ||||
| **Obtaining the Library** | ||||
| 
 | ||||
| The `x-data-spreadsheet` NodeJS packages include a minified script that can be | ||||
| directly inserted as a script tag.  The unpkg CDN also serves this script: | ||||
| 
 | ||||
| ```html | ||||
| <!-- x-spreadsheet stylesheet --> | ||||
| <link rel="stylesheet" href="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.css"/> | ||||
| <!-- x-spreadsheet library --> | ||||
| <script src="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.js"></script> | ||||
| ``` | ||||
| 
 | ||||
| **Previewing and Editing Data** | ||||
| 
 | ||||
| The HTML document needs a container element: | ||||
| 
 | ||||
| ```html | ||||
| <div id="gridctr"></div> | ||||
| ``` | ||||
| 
 | ||||
| Grid initialization is a one-liner: | ||||
| 
 | ||||
| ```js | ||||
| var grid = x_spreadsheet(document.getElementById("gridctr")); | ||||
| ``` | ||||
| 
 | ||||
| `x-spreadsheet` handles the entire edit cycle. No intervention is necessary. | ||||
| 
 | ||||
| **SheetJS and x-spreadsheet** | ||||
| 
 | ||||
| The integration library can be downloaded from the SheetJS CDN: | ||||
| 
 | ||||
| [Development Use](https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js) | ||||
| 
 | ||||
| [Production Use](https://cdn.sheetjs.com/xspreadsheet/xlsxspread.min.js) | ||||
| 
 | ||||
| 
 | ||||
| When used in a browser tag, it exposes two functions: `xtos` and `stox`. | ||||
| 
 | ||||
| - `stox(worksheet)` returns a data structure suitable for `grid.loadData` | ||||
| - `xtos(data)` accepts the result of `grid.getData` and generates a workbook | ||||
| 
 | ||||
| _Reading Data_ | ||||
| 
 | ||||
| The following snippet fetches a spreadsheet and loads the grid: | ||||
| 
 | ||||
| ```js | ||||
| (async() => { | ||||
|   const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); | ||||
|   grid.loadData(stox(XLSX.read(ab))); | ||||
| })(); | ||||
| ``` | ||||
| 
 | ||||
| The same pattern can be used in file input elements and other data sources. | ||||
| 
 | ||||
| _Writing Data_ | ||||
| 
 | ||||
| The following snippet exports the grid data to a file: | ||||
| 
 | ||||
| ```js | ||||
| /* build workbook from the grid data */ | ||||
| XLSX.writeFile(xtos(grid.getData()), "SheetJS.xlsx"); | ||||
| ``` | ||||
| 
 | ||||
| **Additional Features** | ||||
| 
 | ||||
| This demo barely scratches the surface.  The underlying grid component includes | ||||
| many additional features that work with [SheetJS Pro](https://sheetjs.com/pro). | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### Canvas DataGrid | ||||
| 
 | ||||
| After extensive testing, [`canvas-datagrid`](https://canvas-datagrid.js.org/demo.html) | ||||
| @ -120,7 +200,6 @@ many additional features including massive data streaming, sorting and styling. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| 
 | ||||
| ### Angular UI Grid | ||||
| 
 | ||||
| :::warning | ||||
| @ -223,7 +302,7 @@ import { WorkSheet, utils } from 'xlsx'; | ||||
| 
 | ||||
| type Row = any[]; | ||||
| 
 | ||||
| function ws_to_rdg(rows: Row[]): WorkSheet { | ||||
| function rdg_to_ws(rows: Row[]): WorkSheet { | ||||
|   return utils.aoa_to_sheet(rows); | ||||
| } | ||||
| ``` | ||||
| @ -361,8 +440,135 @@ export default function App() { | ||||
| 4) run `npm start`.  When you load the dev page in the browser, it will attempt | ||||
| to fetch <https://sheetjs.com/pres.numbers> and load the data. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| The following screenshot was taken from the demo: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### vue3-table-lite | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested against `vue3-table-lite 1.2.4`, VueJS `3.2.37`, ViteJS | ||||
| 3.0.7, and `@vitejs/plugin-vue` 3.0.3 on 2022 August 18 | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| [`vue3-table-lite`](https://vue3-lite-table.vercel.app/) is a data grid built | ||||
| for Vue | ||||
| 
 | ||||
| [A complete example is included below.](#vte-demo) | ||||
| 
 | ||||
| #### Rows and Columns Bindings | ||||
| 
 | ||||
| `vue3-table-lite` presents two bindable attributes: an array of column metadata | ||||
| (`columns`) and an array of objects representing the displayed data (`rows`). | ||||
| Typically both are `ref` objects: | ||||
| 
 | ||||
| 
 | ||||
| ```html | ||||
| <script setup lang="ts"> | ||||
| import { ref } from "vue"; | ||||
| import VueTableLite from "vue3-table-lite/ts"; | ||||
| 
 | ||||
| /* rows */ | ||||
| type Row = any[]; | ||||
| const rows = ref<Row[]>([]); | ||||
| 
 | ||||
| /* columns */ | ||||
| type Column = { field: string; label: string; }; | ||||
| const columns = ref<Column[]>([]); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <vue-table-lite :columns="columns" :rows="rows"></vue-table-lite> | ||||
| </template> | ||||
| ``` | ||||
| 
 | ||||
| These can be mutated through the `value` property in Vue lifecycle methods: | ||||
| 
 | ||||
| ```ts | ||||
| import { onMounted } from "vue"; | ||||
| onMounted(() => { | ||||
|   columns.value = [ { field: "name", label: "Names" }]; | ||||
|   rows.value = [ { name: "SheetJS" }, { name: "VueJS" } ]; | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| The most generic data representation is an array of arrays. To sate the grid, | ||||
| the columns must be objects whose `field` property is the stringified number: | ||||
| 
 | ||||
| ```js | ||||
| import { ref } from "vue"; | ||||
| import { utils } from 'xlsx'; | ||||
| 
 | ||||
| /* generate row and column data */ | ||||
| function ws_to_vte(ws) { | ||||
|   /* create an array of arrays */ | ||||
|   const rows = utils.sheet_to_json(ws, { header: 1 }); | ||||
| 
 | ||||
|   /* create column array */ | ||||
|   const range = utils.decode_range(ws["!ref"]||"A1"); | ||||
|   const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({ | ||||
|     field: String(i), // VTE will access row["0"], row["1"], etc | ||||
|     label: utils.encode_col(i), // the column labels will be A, B, etc | ||||
|   })); | ||||
| 
 | ||||
|   return { rows, columns }; | ||||
| } | ||||
| 
 | ||||
| const rows = ref([]); | ||||
| const columns = ref([]); | ||||
| 
 | ||||
| /* update refs */ | ||||
| function update_refs(ws) { | ||||
|   const data = ws_to_vte(ws); | ||||
|   rows.value = data.rows; | ||||
|   columns.value = data.columns; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| In the other direction, a worksheet can be generated with `aoa_to_sheet`: | ||||
| 
 | ||||
| ```js | ||||
| import { utils } from 'xlsx'; | ||||
| 
 | ||||
| const rows = ref([]); | ||||
| 
 | ||||
| function vte_to_ws(rows) { | ||||
|   return utils.aoa_to_sheet(rows.value); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| #### VTE Demo | ||||
| 
 | ||||
| <details><summary><b>Complete Example</b> (click to show)</summary> | ||||
| 
 | ||||
| 1) Create a new ViteJS App using the Vue + TypeScript template: | ||||
| 
 | ||||
| ```bash | ||||
| npm create vite@latest sheetjs-vue -- --template vue-ts | ||||
| cd sheetjs-vue | ||||
| ``` | ||||
| 
 | ||||
| 2) Install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npm i | ||||
| npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz vue3-table-lite | ||||
| ``` | ||||
| 
 | ||||
| 3) Download [`src/App.vue`](pathname:///vtl/App.vue) and replace the contents: | ||||
| 
 | ||||
| ```bash | ||||
| cd src | ||||
| rm -f App.vue | ||||
| curl -LO https://docs.sheetjs.com/vtl/App.vue | ||||
| cd .. | ||||
| ``` | ||||
| 
 | ||||
| 4) run `npm run dev`.  When you load the dev page in the browser, it will try | ||||
| to fetch <https://sheetjs.com/pres.numbers> and load the data. | ||||
| 
 | ||||
| </details> | ||||
|  | ||||
| @ -434,7 +434,7 @@ ready, it will read the hardcoded test file and print the contents as CSV. | ||||
| 
 | ||||
| 5) Run the script using the Hermes standalone binary: | ||||
| 
 | ||||
| ``` | ||||
| ```bash | ||||
| hermes xlsx.hermes.js | ||||
| ``` | ||||
| 
 | ||||
| @ -540,6 +540,93 @@ to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ## JerryScript | ||||
| 
 | ||||
| JerryScript is a lightweight JavaScript engine designed for use in low-memory | ||||
| environments like microcontrollers.  As part of the build suite, the project | ||||
| generates a C library and a standalone CLI tool. | ||||
| 
 | ||||
| The simplest way to interact with the engine is to pass Base64 strings. | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| While applications should link against the official libraries, the standalone tool | ||||
| is useful for verifying functionality. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| This demo requires a much larger heap size than is normally used in JerryScript | ||||
| deployments! In local testing, the following sizes were needed: | ||||
| 
 | ||||
| - 8192 (8M) for <https://sheetjs.com/pres.xlsx> | ||||
| - 65536 (64M) for <https://sheetjs.com/pres.numbers> | ||||
| 
 | ||||
| This works on a Raspberry Pi. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| <details><summary><b>Complete Example</b> (click to show)</summary> | ||||
| 
 | ||||
| Due to limitations of the standalone binary, this demo will encode a test file | ||||
| as a Base64 string and directly add it to an amalgamated script. | ||||
| 
 | ||||
| 0) Build the library and command line tool with required options: | ||||
| 
 | ||||
| ```bash | ||||
| git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git | ||||
| cd jerryscript | ||||
| python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON | ||||
| ``` | ||||
| 
 | ||||
| 1) Download the standalone script, shim, and test file: | ||||
| 
 | ||||
| <ul> | ||||
| <li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li> | ||||
| <li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li> | ||||
| <li><a href="https://sheetjs.com/pres.xlsx">pres.xlsx</a></li> | ||||
| </ul> | ||||
| 
 | ||||
| 2) Bundle the test file and create `payload.js`: | ||||
| 
 | ||||
| ```bash | ||||
| node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')" | ||||
| ``` | ||||
| 
 | ||||
| 3) Create support scripts: | ||||
| 
 | ||||
| - `global.js` creates a `global` variable and defines a fake `console`: | ||||
| 
 | ||||
| ```js title="global.js" | ||||
| var global = (function(){ return this; }).call(null); | ||||
| var console = { log: function(x) { print(x); } }; | ||||
| ``` | ||||
| 
 | ||||
| - `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`: | ||||
| 
 | ||||
| ```js title="jerry.js" | ||||
| /* sheetjs (C) 2013-present  SheetJS -- http://sheetjs.com */ | ||||
| var wb = XLSX.read(payload, {type:'base64'}); | ||||
| console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); | ||||
| ``` | ||||
| 
 | ||||
| 4) Create the amalgamation `xlsx.jerry.js`: | ||||
| 
 | ||||
| ```bash | ||||
| cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js | ||||
| ``` | ||||
| 
 | ||||
| The final script defines `global` before loading the standalone library.  Once | ||||
| ready, it will read the hardcoded test file and print the contents as CSV. | ||||
| 
 | ||||
| 5) Run the script using the `jerry` standalone binary: | ||||
| 
 | ||||
| ```bash | ||||
| build/bin/jerry xlsx.jerry.js; echo $? | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ## QuickJS | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| --- | ||||
| sidebar_position: 20 | ||||
| sidebar_position: 21 | ||||
| title: ReactJS | ||||
| --- | ||||
| 
 | ||||
| @ -38,7 +38,7 @@ Typically, some users will create a spreadsheet with source data that should be | ||||
| loaded into the site.  This sheet will have known columns.  For example, our | ||||
| [presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns: | ||||
| 
 | ||||
|  | ||||
|  | ||||
| 
 | ||||
| This naturally maps to an array of typed objects, as in the TS example below: | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										184
									
								
								docz/docs/03-demos/22-vue.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										184
									
								
								docz/docs/03-demos/22-vue.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,184 @@ | ||||
| --- | ||||
| sidebar_position: 22 | ||||
| title: VueJS | ||||
| --- | ||||
| 
 | ||||
| [VueJS](https://vuejs.org/) is a JS library for building user interfaces. | ||||
| 
 | ||||
| This demo tries to cover common Vue data flow ideas and strategies. Single-File | ||||
| Components (SFC) and VueJS familiarity is assumed. | ||||
| 
 | ||||
| Other demos cover general VueJS deployments, including: | ||||
| 
 | ||||
| - [Static Site Generation powered by NuxtJS](./content#nuxtjs) | ||||
| - [iOS and Android applications powered by Quasar](./mobile#quasar) | ||||
| - [`vue3-table-lite` UI component](./grid#vue3-table-lite) | ||||
| 
 | ||||
| 
 | ||||
| ## Installation | ||||
| 
 | ||||
| [The "Frameworks" section](../getting-started/installation/frameworks) covers | ||||
| installation with Yarn and other package managers. | ||||
| 
 | ||||
| The library can be imported directly from JS or JSX code with: | ||||
| 
 | ||||
| ```js | ||||
| import { read, utils, writeFile } from 'xlsx'; | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| ## Internal State | ||||
| 
 | ||||
| The various SheetJS APIs work with various data shapes.  The preferred state | ||||
| depends on the application. | ||||
| 
 | ||||
| ### Array of Objects | ||||
| 
 | ||||
| Typically, some users will create a spreadsheet with source data that should be | ||||
| loaded into the site.  This sheet will have known columns.  For example, our | ||||
| [presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| This naturally maps to an array of typed objects, as in the TS example below: | ||||
| 
 | ||||
| ```ts | ||||
| import { read, utils } from 'xlsx'; | ||||
| 
 | ||||
| interface President { | ||||
|   Name: string; | ||||
|   Index: number; | ||||
| } | ||||
| 
 | ||||
| const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); | ||||
| const wb = read(f); | ||||
| const data = utils.sheet_to_json<President>(wb.Sheets[wb.SheetNames[0]]); | ||||
| console.log(data); | ||||
| ``` | ||||
| 
 | ||||
| `data` will be an array of objects: | ||||
| 
 | ||||
| ```js | ||||
| [ | ||||
|   { Name: "Bill Clinton", Index: 42 }, | ||||
|   { Name: "GeorgeW Bush", Index: 43 }, | ||||
|   { Name: "Barack Obama", Index: 44 }, | ||||
|   { Name: "Donald Trump", Index: 45 }, | ||||
|   { Name: "Joseph Biden", Index: 46 } | ||||
| ] | ||||
| ``` | ||||
| 
 | ||||
| A component will typically map over the data. The following example generates | ||||
| a TABLE with a row for each President: | ||||
| 
 | ||||
| ```html title="src/SheetJSVueAoO.vue" | ||||
| <script setup> | ||||
| import { ref, onMounted } from "vue"; | ||||
| import { read, utils } from 'xlsx'; | ||||
| 
 | ||||
| const rows = ref([]); | ||||
| 
 | ||||
| onMounted(async() => { | ||||
|   /* Download from https://sheetjs.com/pres.numbers */ | ||||
|   const f = await fetch("https://sheetjs.com/pres.numbers"); | ||||
|   const ab = await f.arrayBuffer(); | ||||
| 
 | ||||
|   /* parse workbook */ | ||||
|   const wb = read(ab); | ||||
| 
 | ||||
|   /* update data */ | ||||
|   rows.value = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <table><thead><th>Name</th><th>Index</th></thead><tbody> | ||||
|     <tr v-for="(row, idx) in rows" :key="idx"> | ||||
|       <td>{{ row.Name }}</td> | ||||
|       <td>{{ row.Index }}</td> | ||||
|     </tr> | ||||
|   </tbody></table> | ||||
| </template> | ||||
| ``` | ||||
| 
 | ||||
| ### HTML | ||||
| 
 | ||||
| The main disadvantage of the Array of Objects approach is the specific nature | ||||
| of the columns.  For more general use, passing around an Array of Arrays works. | ||||
| However, this does not handle merge cells well! | ||||
| 
 | ||||
| The `sheet_to_html` function generates HTML that is aware of merges and other | ||||
| worksheet features.  VueJS `v-html` attribute allows assignment of `innerHTML` | ||||
| attribute, effectively inserting the code into the page: | ||||
| 
 | ||||
| ```html title="src/SheetJSVueHTML.vue" | ||||
| <script setup> | ||||
| import { ref, onMounted } from "vue"; | ||||
| import { read, utils } from 'xlsx'; | ||||
| 
 | ||||
| const html = ref(""); | ||||
| 
 | ||||
| onMounted(async() => { | ||||
|   /* Download from https://sheetjs.com/pres.numbers */ | ||||
|   const f = await fetch("https://sheetjs.com/pres.numbers"); | ||||
|   const ab = await f.arrayBuffer(); | ||||
| 
 | ||||
|   /* parse workbook */ | ||||
|   const wb = read(ab); | ||||
| 
 | ||||
|   /* update data */ | ||||
|   html.value = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div v-html="html"></div> | ||||
| </template> | ||||
| ``` | ||||
| 
 | ||||
| ### Rows and Columns | ||||
| 
 | ||||
| Some data grids and UI components split worksheet state in two parts: an array | ||||
| of column attribute objects and an array of row objects.  The former is used to | ||||
| generate column headings and for indexing into the row objects. | ||||
| 
 | ||||
| The safest approach is to use an array of arrays for state and to generate | ||||
| column objects that map to A1-style column headers. | ||||
| 
 | ||||
| The [Vue Table Lite demo](./grid#rows-and-columns-bindings) uses this approach | ||||
| with the following column and row structure: | ||||
| 
 | ||||
| ```js | ||||
| /* rows are generated with a simple array of arrays */ | ||||
| rows.value = utils.sheet_to_json(worksheet, { header: 1 }); | ||||
| 
 | ||||
| /* column objects are generated based on the worksheet range */ | ||||
| const range = utils.decode_range(ws["!ref"]||"A1"); | ||||
| columns.value = Array.from({ length: range.e.c + 1 }, (_, i) => ({ | ||||
|   /* for an array of arrays, the keys are "0", "1", "2", ... */ | ||||
|   field: String(i), | ||||
|   /* column labels: encode_col translates 0 -> "A", 1 -> "B", 2 -> "C", ... */ | ||||
|   label: XLSX.utils.encode_col(i) | ||||
| })); | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| ## Legacy Deployments | ||||
| 
 | ||||
| [The Standalone Scripts](../getting-started/installation/standalone) play nice | ||||
| with legacy deployments that do not use a bundler. | ||||
| 
 | ||||
| The legacy demos show a simple VueJS component.  It is written in ES5 syntax. | ||||
| The pages are not minified and "View Source" should be used to inspect. | ||||
| 
 | ||||
| - [VueJS version 2](pathname:///vue/index2.html) | ||||
| - [VueJS version 3](pathname:///vue/index3.html) | ||||
| 
 | ||||
| There is a shared component [`SheetJS-vue.js`](pathname:///vue/SheetJS-vue.js) | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| The entire demo is designed to run in Internet Explorer and does not reflect | ||||
| modern design patterns. | ||||
| 
 | ||||
| ::: | ||||
| @ -18,18 +18,18 @@ The demo projects include small runnable examples and short explainers. | ||||
| 
 | ||||
| ### Frameworks | ||||
| 
 | ||||
| - [`Angular.JS`](./legacy#angularjs) | ||||
| - [`Angular 2+ and Ionic`](https://github.com/SheetJS/SheetJS/tree/master/demos/angular2/) | ||||
| - [`Knockout`](./legacy#knockout) | ||||
| - [`React`](./react) | ||||
| - [`VueJS`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/) | ||||
| - [`VueJS`](./vue) | ||||
| - [`Angular.JS`](./legacy#angularjs) | ||||
| - [`Knockout`](./legacy#knockout) | ||||
| 
 | ||||
| ### Front-End UI Components | ||||
| 
 | ||||
| - [`canvas-datagrid`](./grid#canvas-datagrid) | ||||
| - [`x-spreadsheet`](https://github.com/SheetJS/SheetJS/tree/master/demos/xspreadsheet/) | ||||
| - [`react-data-grid`](https://github.com/SheetJS/SheetJS/tree/master/demos/react/modify/) | ||||
| - [`vue3-table-light`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/modify/) | ||||
| - [`x-spreadsheet`](./grid#x-spreadsheet) | ||||
| - [`react-data-grid`](./grid#react-data-grid) | ||||
| - [`vue3-table-lite`](./grid#vue3-table-lite) | ||||
| - [`angular-ui-grid`](./grid#angular-ui-grid) | ||||
| 
 | ||||
| ### Platforms and Integrations | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */ | ||||
| /* sheetjs (C) 2013-present  SheetJS -- http://sheetjs.com */ | ||||
| var XLSX = require('xlsx'); | ||||
| /*jshint browser:true */ | ||||
| /*global require */ | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- sheetjs (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- vim: set ts=2: --> | ||||
| <html> | ||||
| <head> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| var XLSX = require('xlsx'); | ||||
| 
 | ||||
| postMessage({t:"ready"}); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- sheetjs (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- vim: set ts=2: --> | ||||
| <html> | ||||
| <head> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- sheetjs (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- vim: set ts=2: --> | ||||
| <html ng-app="sjs"> | ||||
| <head> | ||||
|  | ||||
| Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB | 
| @ -3,156 +3,156 @@ | ||||
| <!-- vim: set ts=2: --> | ||||
| <html lang="en" style="height: 100%"> | ||||
| <head> | ||||
| 	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||||
| 	<title>SheetJS React Demo</title> | ||||
| 	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> | ||||
| 	<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> | ||||
| 	<script src="https://unpkg.com/react/umd/react.production.min.js"></script> | ||||
| 	<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script> | ||||
| 	<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script> | ||||
| 	<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script> | ||||
| 	<style>body, #app { height: 100%; }</style> | ||||
|   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||||
|   <title>SheetJS React Demo</title> | ||||
|   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> | ||||
|   <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> | ||||
|   <script src="https://unpkg.com/react/umd/react.production.min.js"></script> | ||||
|   <script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script> | ||||
|   <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script> | ||||
|   <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script> | ||||
|   <style>body, #app { height: 100%; }</style> | ||||
| </head> | ||||
| <body> | ||||
| 	<div class="container-fluid"><h1><a href="http://sheetjs.com">SheetJS × React Demo</a></h1><br /></div> | ||||
| 	<div id="app" class="container-fluid"></div> | ||||
| 	<script type="text/babel"> | ||||
| 		/* sheetjs (C) 2013-present  SheetJS -- http://sheetjs.com */ | ||||
| 		/* Notes: | ||||
| 			 - usage: `ReactDOM.render( <SheetJSApp />, document.getElementById('app') );` | ||||
| 			 - xlsx.full.min.js is loaded in the head of the HTML page | ||||
| 			 - this script should be referenced with type="text/babel" | ||||
| 			 - babel.js in-browser transpiler should be loaded before this script | ||||
| 		*/ | ||||
| 		const { read, writeFile } = XLSX; | ||||
| 		const { decode_range, encode_col, sheet_to_json, aoa_to_sheet, book_new, book_append_sheet } = XLSX.utils; | ||||
|   <div class="container-fluid"><h1><a href="http://sheetjs.com">SheetJS × React Demo</a></h1><br /></div> | ||||
|   <div id="app" class="container-fluid"></div> | ||||
|   <script type="text/babel"> | ||||
|     /* sheetjs (C) 2013-present  SheetJS -- http://sheetjs.com */ | ||||
|     /* Notes: | ||||
|        - usage: `ReactDOM.render( <SheetJSApp />, document.getElementById('app') );` | ||||
|        - xlsx.full.min.js is loaded in the head of the HTML page | ||||
|        - this script should be referenced with type="text/babel" | ||||
|        - babel.js in-browser transpiler should be loaded before this script | ||||
|     */ | ||||
|     const { read, writeFile } = XLSX; | ||||
|     const { decode_range, encode_col, sheet_to_json, aoa_to_sheet, book_new, book_append_sheet } = XLSX.utils; | ||||
| 
 | ||||
| 		/* generate an array of column objects */ | ||||
| 		const make_cols = refstr => Array.from({length: decode_range(refstr).e.c + 1}, (_, i) => ({ name: encode_col(i), key: i})); | ||||
|     /* generate an array of column objects */ | ||||
|     const make_cols = refstr => Array.from({length: decode_range(refstr).e.c + 1}, (_, i) => ({ name: encode_col(i), key: i})); | ||||
| 
 | ||||
| 		/* main component */ | ||||
| 		function SheetJSApp() { | ||||
| 			const [data, setData] = React.useState([]); | ||||
| 			const [cols, setCols] = React.useState([]); | ||||
|     /* main component */ | ||||
|     function SheetJSApp() { | ||||
|       const [data, setData] = React.useState([]); | ||||
|       const [cols, setCols] = React.useState([]); | ||||
| 
 | ||||
| 			const handleFile = (file) => { | ||||
| 				const reader = new FileReader(); | ||||
| 				reader.onload = (e) => { | ||||
| 					/* Parse data */ | ||||
| 					const ab = e.target.result; | ||||
| 					const wb = read(ab, { type: 'array' }); | ||||
| 					/* Get first worksheet */ | ||||
| 					const wsname = wb.SheetNames[0]; | ||||
| 					const ws = wb.Sheets[wsname]; | ||||
| 					/* Convert array of arrays */ | ||||
| 					const data = sheet_to_json(ws, { header: 1 }); | ||||
| 					/* Update state */ | ||||
| 					setData(data); | ||||
| 					setCols(make_cols(ws['!ref'])) | ||||
| 				}; | ||||
| 				reader.readAsArrayBuffer(file); | ||||
| 			} | ||||
|       const handleFile = (file) => { | ||||
|         const reader = new FileReader(); | ||||
|         reader.onload = (e) => { | ||||
|           /* Parse data */ | ||||
|           const ab = e.target.result; | ||||
|           const wb = read(ab, { type: 'array' }); | ||||
|           /* Get first worksheet */ | ||||
|           const wsname = wb.SheetNames[0]; | ||||
|           const ws = wb.Sheets[wsname]; | ||||
|           /* Convert array of arrays */ | ||||
|           const data = sheet_to_json(ws, { header: 1 }); | ||||
|           /* Update state */ | ||||
|           setData(data); | ||||
|           setCols(make_cols(ws['!ref'])) | ||||
|         }; | ||||
|         reader.readAsArrayBuffer(file); | ||||
|       } | ||||
| 
 | ||||
| 			const exportFile = () => { | ||||
| 				/* convert state to workbook */ | ||||
| 				const ws = aoa_to_sheet(data); | ||||
| 				const wb = book_new(); | ||||
| 				book_append_sheet(wb, ws, "SheetJS"); | ||||
| 				/* generate XLSX file and send to client */ | ||||
| 				writeFile(wb, "sheetjs.xlsx") | ||||
| 			}; | ||||
|       const exportFile = () => { | ||||
|         /* convert state to workbook */ | ||||
|         const ws = aoa_to_sheet(data); | ||||
|         const wb = book_new(); | ||||
|         book_append_sheet(wb, ws, "SheetJS"); | ||||
|         /* generate XLSX file and send to client */ | ||||
|         writeFile(wb, "sheetjs.xlsx") | ||||
|       }; | ||||
| 
 | ||||
| 			return ( | ||||
| 				<DragDropFile handleFile={handleFile}> | ||||
| 					<div className="row"><div className="col-xs-12"> | ||||
| 						<DataInput handleFile={handleFile} /> | ||||
| 					</div></div> | ||||
| 					<div className="row"><div className="col-xs-12"> | ||||
| 						{data.length ? <button className="btn btn-success" onClick={exportFile}>Export</button> : ""} | ||||
| 					</div></div> | ||||
| 					<div className="row"><div className="col-xs-12"> | ||||
| 						<OutTable data={data} cols={cols} /> | ||||
| 					</div></div> | ||||
| 				</DragDropFile> | ||||
| 			); | ||||
| 		} | ||||
|       return ( | ||||
|         <DragDropFile handleFile={handleFile}> | ||||
|           <div className="row"><div className="col-xs-12"> | ||||
|             <DataInput handleFile={handleFile} /> | ||||
|           </div></div> | ||||
|           <div className="row"><div className="col-xs-12"> | ||||
|             {data.length ? <button className="btn btn-success" onClick={exportFile}>Export</button> : ""} | ||||
|           </div></div> | ||||
|           <div className="row"><div className="col-xs-12"> | ||||
|             <OutTable data={data} cols={cols} /> | ||||
|           </div></div> | ||||
|         </DragDropFile> | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
| 		/* -------------------------------------------------------------------------- */ | ||||
|     /* -------------------------------------------------------------------------- */ | ||||
| 
 | ||||
| 		/* | ||||
| 			Simple HTML5 file drag-and-drop wrapper | ||||
| 			usage: <DragDropFile handleFile={handleFile}>...</DragDropFile> | ||||
| 				handleFile(file:File):void; | ||||
| 		*/ | ||||
|     /* | ||||
|       Simple HTML5 file drag-and-drop wrapper | ||||
|       usage: <DragDropFile handleFile={handleFile}>...</DragDropFile> | ||||
|         handleFile(file:File):void; | ||||
|     */ | ||||
| 
 | ||||
| 		function DragDropFile({ handleFile, children }) { | ||||
| 			const suppress = (e) => { e.stopPropagation(); e.preventDefault(); }; | ||||
| 			const handleDrop = (e) => { | ||||
| 				e.stopPropagation(); e.preventDefault(); | ||||
| 				const files = e.dataTransfer.files; | ||||
| 				if (files && files[0]) handleFile(files[0]); | ||||
| 			}; | ||||
|     function DragDropFile({ handleFile, children }) { | ||||
|       const suppress = (e) => { e.stopPropagation(); e.preventDefault(); }; | ||||
|       const handleDrop = (e) => { | ||||
|         e.stopPropagation(); e.preventDefault(); | ||||
|         const files = e.dataTransfer.files; | ||||
|         if (files && files[0]) handleFile(files[0]); | ||||
|       }; | ||||
| 
 | ||||
| 			return ( <div onDrop={handleDrop} onDragEnter={suppress} onDragOver={suppress}>{children}</div> ); | ||||
| 		} | ||||
|       return ( <div onDrop={handleDrop} onDragEnter={suppress} onDragOver={suppress}>{children}</div> ); | ||||
|     } | ||||
| 
 | ||||
| 		/* | ||||
| 			Simple HTML5 file input wrapper | ||||
| 			usage: <DataInput handleFile={callback} /> | ||||
| 				handleFile(file:File):void; | ||||
| 		*/ | ||||
|     /* | ||||
|       Simple HTML5 file input wrapper | ||||
|       usage: <DataInput handleFile={callback} /> | ||||
|         handleFile(file:File):void; | ||||
|     */ | ||||
| 
 | ||||
| 		function DataInput({ handleFile }) { | ||||
| 			const handleChange = (e) => { | ||||
| 				const files = e.target.files; | ||||
| 				if (files && files[0]) handleFile(files[0]); | ||||
| 			}; | ||||
|     function DataInput({ handleFile }) { | ||||
|       const handleChange = (e) => { | ||||
|         const files = e.target.files; | ||||
|         if (files && files[0]) handleFile(files[0]); | ||||
|       }; | ||||
| 
 | ||||
| 			return ( | ||||
| 				<form className="form-inline"> | ||||
| 					<div className="form-group"> | ||||
| 						<label htmlFor="file">Drag or choose a spreadsheet file</label><br /> | ||||
| 						<input type="file" className="form-control" id="file" accept={SheetJSFT} onChange={handleChange} /> | ||||
| 					</div> | ||||
| 				</form> | ||||
| 			) | ||||
| 		} | ||||
| 		/* list of supported file types */ | ||||
| 		const SheetJSFT = [ | ||||
| 			"xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm" | ||||
| 		].map(x => `.${x}`).join(","); | ||||
|       return ( | ||||
|         <form className="form-inline"> | ||||
|           <div className="form-group"> | ||||
|             <label htmlFor="file">Drag or choose a spreadsheet file</label><br /> | ||||
|             <input type="file" className="form-control" id="file" accept={SheetJSFT} onChange={handleChange} /> | ||||
|           </div> | ||||
|         </form> | ||||
|       ) | ||||
|     } | ||||
|     /* list of supported file types */ | ||||
|     const SheetJSFT = [ | ||||
|       "xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm" | ||||
|     ].map(x => `.${x}`).join(","); | ||||
| 
 | ||||
| 		/* | ||||
| 			Simple HTML Table | ||||
| 			usage: <OutTable data={data} cols={cols} /> | ||||
| 				data:Array<Array<any> >; | ||||
| 				cols:Array<{name:string, key:number|string}>; | ||||
| 		*/ | ||||
| 		function OutTable({ data, cols }) { | ||||
| 			return ( | ||||
| 				<div className="table-responsive"> | ||||
| 					<table className="table table-striped"> | ||||
| 						<thead> | ||||
| 							<tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr> | ||||
| 						</thead> | ||||
| 						<tbody> | ||||
| 							{data.map((r, i) => <tr key={i}> | ||||
| 								{cols.map(c => <td key={c.key}>{r[c.key]}</td>)} | ||||
| 							</tr>)} | ||||
| 						</tbody> | ||||
| 					</table> | ||||
| 				</div> | ||||
| 			); | ||||
| 		} | ||||
|     /* | ||||
|       Simple HTML Table | ||||
|       usage: <OutTable data={data} cols={cols} /> | ||||
|         data:Array<Array<any> >; | ||||
|         cols:Array<{name:string, key:number|string}>; | ||||
|     */ | ||||
|     function OutTable({ data, cols }) { | ||||
|       return ( | ||||
|         <div className="table-responsive"> | ||||
|           <table className="table table-striped"> | ||||
|             <thead> | ||||
|               <tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr> | ||||
|             </thead> | ||||
|             <tbody> | ||||
|               {data.map((r, i) => <tr key={i}> | ||||
|                 {cols.map(c => <td key={c.key}>{r[c.key]}</td>)} | ||||
|               </tr>)} | ||||
|             </tbody> | ||||
|           </table> | ||||
|         </div> | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
| 		/* React 18 uses ReactDOM.createRoot; < 18 should use ReactDOM.render */ | ||||
| 		const root_elt = document.getElementById('app'); | ||||
| 		if(typeof ReactDOM.createRoot !== "undefined") { | ||||
| 			const root = ReactDOM.createRoot(root_elt); | ||||
| 			root.render(<SheetJSApp/>); | ||||
| 		} else { | ||||
| 			ReactDOM.render(<SheetJSApp />, root_elt); | ||||
| 		} | ||||
| 	</script> | ||||
|     /* React 18 uses ReactDOM.createRoot; < 18 should use ReactDOM.render */ | ||||
|     const root_elt = document.getElementById('app'); | ||||
|     if(typeof ReactDOM.createRoot !== "undefined") { | ||||
|       const root = ReactDOM.createRoot(root_elt); | ||||
|       root.render(<SheetJSApp/>); | ||||
|     } else { | ||||
|       ReactDOM.render(<SheetJSApp />, root_elt); | ||||
|     } | ||||
|   </script> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										219
									
								
								docz/static/vtl/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										219
									
								
								docz/static/vtl/App.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,219 @@ | ||||
| <script setup lang="ts"> | ||||
| /*! sheetjs (C) SheetJS -- http://sheetjs.com */ | ||||
| import { ref, onMounted } from "vue"; | ||||
| import VueTableLite from "vue3-table-lite/ts"; | ||||
| import { read, utils, WorkSheet, writeFile } from "xlsx"; | ||||
| 
 | ||||
| type DataSet = { [index: string]: WorkSheet; }; | ||||
| type Row = any[]; | ||||
| type RowCB = (row: Row) => string; | ||||
| type Column = { field: string; label: string; display: RowCB; }; | ||||
| type RowCol = { rows: Row[]; cols: Column[]; }; | ||||
| 
 | ||||
| const currFileName = ref<string>(""); | ||||
| const currSheet = ref<string>(""); | ||||
| const sheets = ref<string[]>([]); | ||||
| const workBook = ref<DataSet>({} as DataSet); | ||||
| const rows = ref<Row[]>([]); | ||||
| const columns = ref<Column[]>([]); | ||||
| 
 | ||||
| const exportTypes: string[] = ["xlsx", "xlsb", "csv", "html"]; | ||||
| 
 | ||||
| let cell = 0; | ||||
| 
 | ||||
| function resetCell() { | ||||
|   cell = 0; | ||||
| } | ||||
| 
 | ||||
| const getRowsCols = ( data: DataSet, sheetName: string ): RowCol => ({ | ||||
|   rows: utils.sheet_to_json<Row>(data[sheetName], {header:1}), | ||||
|   cols: Array.from({ | ||||
|     length: utils.decode_range(data[sheetName]["!ref"]||"A1").e.c + 1 | ||||
|   }, (_, i) => (<Column>{ field: String(i), label: utils.encode_col(i), display: makeDisplay(i) })) | ||||
| }); | ||||
| 
 | ||||
| const makeDisplay = (col: number): RowCB => (row: Row) => `<span | ||||
|   style="user-select: none; display: block" | ||||
|   onblur="endEdit(event)" ondblclick="startEdit(event)" | ||||
|   position="${Math.floor(cell++ / columns.value.length)}.${col}" | ||||
|   onkeydown="endEdit(event)">${row?.[col] ?? " "}</span>`; | ||||
| 
 | ||||
| (window as any).startEdit = function (ev: MouseEvent) { | ||||
|   (ev?.target as HTMLSpanElement).contentEditable = "true"; | ||||
|   (ev?.target as HTMLSpanElement).focus(); | ||||
| }; | ||||
| 
 | ||||
| (window as any).endEdit = function (ev: FocusEvent | KeyboardEvent) { | ||||
|   if (typeof (ev as KeyboardEvent).key == "undefined" || (ev as KeyboardEvent).key === "Enter") { | ||||
|     const pos = (ev.target as HTMLSpanElement)?.getAttribute("position")?.split("."); | ||||
|     if(!pos) return; | ||||
| 
 | ||||
|     (ev?.target as HTMLSpanElement).contentEditable = "true"; | ||||
| 
 | ||||
|     rows.value[+pos[0]][+pos[1]] = (ev.target as HTMLSpanElement).innerText; | ||||
| 
 | ||||
|     workBook.value[currSheet.value] = utils.json_to_sheet(rows.value, { | ||||
|       header: columns.value.map((col: Column) => col.field), | ||||
|       skipHeader: true, | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| async function importAB(ab: ArrayBuffer, name: string): Promise<void> { | ||||
|   const data = read(ab); | ||||
| 
 | ||||
|   currFileName.value = name; | ||||
|   currSheet.value = data.SheetNames?.[0]; | ||||
|   sheets.value = data.SheetNames; | ||||
|   workBook.value = data.Sheets; | ||||
| 
 | ||||
|   selectSheet(currSheet.value); | ||||
| } | ||||
| 
 | ||||
| async function importFile(ev: Event): Promise<void> { | ||||
|   const file = (ev.target as HTMLInputElement)?.files?.[0]; | ||||
|   if(!file) return; | ||||
|   await importAB(await file.arrayBuffer(), file.name); | ||||
| } | ||||
| 
 | ||||
| function exportFile(type: string): void { | ||||
|   const wb = utils.book_new(); | ||||
| 
 | ||||
|   sheets.value.forEach((sheet) => { | ||||
|     utils.book_append_sheet(wb, workBook.value[sheet], sheet); | ||||
|   }); | ||||
| 
 | ||||
|   writeFile(wb, `sheet.${type}`); | ||||
| } | ||||
| 
 | ||||
| function selectSheet(sheet: string): void { | ||||
|   const { rows: newRows, cols: newCols } = getRowsCols(workBook.value, sheet); | ||||
| 
 | ||||
|   resetCell(); | ||||
| 
 | ||||
|   rows.value = newRows; | ||||
|   columns.value = newCols; | ||||
|   currSheet.value = sheet; | ||||
| } | ||||
| 
 | ||||
| /* Download from https://sheetjs.com/pres.numbers */ | ||||
| onMounted(async() => { | ||||
|   const response = await fetch("https://sheetjs.com/pres.numbers"); | ||||
|   await importAB(await response.arrayBuffer(), "pres.numbers"); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <header class="imp-exp"> | ||||
|     <div class="import"> | ||||
|       <input type="file" id="import" @change="importFile" /> | ||||
|       <label for="import">import</label> | ||||
|     </div> | ||||
|     <span v-if="currFileName">{{ currFileName }}</span> | ||||
|     <div class="export" v-if="currFileName"> | ||||
|       <span>export</span> | ||||
|       <ul> | ||||
|         <li v-for="(type, idx) in exportTypes" :key="idx" @click="exportFile(type)"> | ||||
|           {{ `.${type}` }} | ||||
|         </li> | ||||
|       </ul> | ||||
|     </div> | ||||
|   </header> | ||||
|   <div class="sheets"> | ||||
|     <span | ||||
|       v-for="(sheet, idx) in sheets" | ||||
|       :key="idx" | ||||
|       @click="selectSheet(sheet)" | ||||
|       :class="[currSheet === sheet ? 'selected' : '']" | ||||
|     > | ||||
|       {{ sheet }} | ||||
|     </span> | ||||
|   </div> | ||||
|   <vue-table-lite :is-static-mode="true" :page-size="50" :columns="columns" :rows="rows"></vue-table-lite> | ||||
| </template> | ||||
| 
 | ||||
| <style> | ||||
| .imp-exp { | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   padding: 0.5rem; | ||||
|   font-family: mono; | ||||
|   color: #212529; | ||||
| } | ||||
| 
 | ||||
| .import { | ||||
|   font-size: medium; | ||||
| } | ||||
| 
 | ||||
| .import input { | ||||
|   position: absolute; | ||||
|   opacity: 0; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .import label { | ||||
|   background-color: white; | ||||
|   border: 1px solid; | ||||
|   padding: 0.3rem; | ||||
| } | ||||
| 
 | ||||
| .export:hover { | ||||
|   border-bottom: none; | ||||
| } | ||||
| 
 | ||||
| .export:hover ul { | ||||
|   display: block; | ||||
| } | ||||
| 
 | ||||
| .export span { | ||||
|   padding: 0.3rem; | ||||
|   border: 1px solid; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .export ul { | ||||
|   display: none; | ||||
|   position: absolute; | ||||
|   z-index: 5; | ||||
|   background-color: white; | ||||
|   list-style: none; | ||||
|   padding: 0.3rem; | ||||
|   border: 1px solid; | ||||
|   margin-top: 0.3rem; | ||||
|   border-top: none; | ||||
| } | ||||
| 
 | ||||
| .export ul li { | ||||
|   padding: 0.3rem; | ||||
|   text-align: center; | ||||
| } | ||||
| 
 | ||||
| .export ul li:hover { | ||||
|   background-color: lightgray; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .sheets { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   margin: 0.3rem; | ||||
|   color: #212529; | ||||
| } | ||||
| 
 | ||||
| .sheets span { | ||||
|   border: 1px solid; | ||||
|   padding: 0.5rem; | ||||
|   margin: 0.3rem; | ||||
| } | ||||
| 
 | ||||
| .sheets span:hover:not(.selected) { | ||||
|   background-color: lightgray; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .selected { | ||||
|   background-color: #343a40; | ||||
|   color: white; | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
							
								
								
									
										60
									
								
								docz/static/vue/SheetJS-vue.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										60
									
								
								docz/static/vue/SheetJS-vue.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| /* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| var SheetJSFT = [ | ||||
|   "xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm", "numbers" | ||||
| ].map(function(x) { return "." + x; }).join(","); | ||||
| 
 | ||||
| var SJSTemplate = [ | ||||
|   '<div>', | ||||
|     '<input type="file" multiple="false" id="sheetjs-input" accept="' + SheetJSFT + '" @change="onchange" />', | ||||
|     '<br/>', | ||||
|     '<button type="button" id="export-table" style="visibility:hidden" @click="onexport">Export to XLSX</button>', | ||||
|     '<br/>', | ||||
|     '<div id="out-table"></div>', | ||||
|   '</div>' | ||||
| ].join(""); | ||||
| var component_struct = { | ||||
|   template: SJSTemplate, | ||||
|   methods: { | ||||
|     onchange: function(evt) { | ||||
|       var files = evt.target.files; | ||||
|       if (!files || files.length == 0) return; | ||||
| 
 | ||||
|       var file = files[0]; | ||||
| 
 | ||||
|       var reader = new FileReader(); | ||||
|       reader.onload = function (e) { | ||||
|         // get data
 | ||||
|         var bytes = new Uint8Array(e.target.result); | ||||
| 
 | ||||
|         /* read workbook */ | ||||
|         var wb = XLSX.read(bytes); | ||||
| 
 | ||||
|         /* grab first sheet */ | ||||
|         var wsname = wb.SheetNames[0]; | ||||
|         var ws = wb.Sheets[wsname]; | ||||
| 
 | ||||
|         /* generate HTML */ | ||||
|         var HTML = XLSX.utils.sheet_to_html(ws); | ||||
| 
 | ||||
|         /* update table */ | ||||
|         document.getElementById('out-table').innerHTML = HTML; | ||||
|         /* show export button */ | ||||
|         document.getElementById('export-table').style.visibility = "visible"; | ||||
|       }; | ||||
| 
 | ||||
|       reader.readAsArrayBuffer(file); | ||||
|     }, | ||||
|     onexport: function(evt) { | ||||
|       /* generate workbook object from table */ | ||||
|       var wb = XLSX.utils.table_to_book(document.getElementById('out-table').getElementsByTagName("TABLE")[0]); | ||||
|       /* generate file and force a download*/ | ||||
|       XLSX.writeFile(wb, "sheetjs.xlsx"); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| if(Vue.component) { | ||||
|   Vue.component('html-preview', component_struct); | ||||
| } else { | ||||
|   var app = Vue.createApp({}); | ||||
|   app.component('html-preview', component_struct); | ||||
| } | ||||
							
								
								
									
										56
									
								
								docz/static/vue/index2.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										56
									
								
								docz/static/vue/index2.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- sheetjs (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- vim: set ts=2: --> | ||||
| <html> | ||||
| <head> | ||||
|   <title>SheetJS + VueJS2</title> | ||||
|   <!-- Vue 2 --> | ||||
|   <script src="https://unpkg.com/vue@2.x"></script> | ||||
| 
 | ||||
|   <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script> | ||||
|   <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script> | ||||
| 
 | ||||
|   <!-- SheetJS Vue components --> | ||||
|   <script src="SheetJS-vue.js"></script> | ||||
| 
 | ||||
| <style> | ||||
| .grid1 { | ||||
|   width: 500px; | ||||
|   height: 400px; | ||||
| }; | ||||
| </style> | ||||
| </head> | ||||
| <body> | ||||
| <pre> | ||||
| <b><a href="http://sheetjs.com">SheetJS + VueJS2 demo</a></b> | ||||
| 
 | ||||
| This demo shows a sample Vue component "html-preview" that: | ||||
| - displays a file input that accepts a spreadsheet file | ||||
| - draws the first worksheet of a submitted file as HTML | ||||
| - presents an export button to generate XLSX files | ||||
| 
 | ||||
| <a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a> | ||||
| </pre> | ||||
| <script type="text/javascript"> | ||||
|   var _gaq = _gaq || []; | ||||
|   _gaq.push(['_setAccount', 'UA-36810333-1']); | ||||
|   _gaq.push(['_trackPageview']); | ||||
| 
 | ||||
|   (function() { | ||||
|     var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | ||||
|     ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | ||||
|     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | ||||
|   })(); | ||||
| </script> | ||||
| 
 | ||||
| <div id="app"> | ||||
|   <html-preview></html-preview> | ||||
| </div> | ||||
| 
 | ||||
| <script lang="javascript"> | ||||
| if(Vue.component) var app = new Vue({ el: '#app' }); | ||||
| else app.mount('#app'); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
							
								
								
									
										56
									
								
								docz/static/vue/index3.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										56
									
								
								docz/static/vue/index3.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- sheetjs (C) 2013-present  SheetJS http://sheetjs.com --> | ||||
| <!-- vim: set ts=2: --> | ||||
| <html> | ||||
| <head> | ||||
|   <title>SheetJS + VueJS3</title> | ||||
|   <!-- Vue 2 --> | ||||
|   <script src="https://unpkg.com/vue@3.x"></script> | ||||
| 
 | ||||
|   <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script> | ||||
|   <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script> | ||||
| 
 | ||||
|   <!-- SheetJS Vue components --> | ||||
|   <script src="SheetJS-vue.js"></script> | ||||
| 
 | ||||
| <style> | ||||
| .grid1 { | ||||
|   width: 500px; | ||||
|   height: 400px; | ||||
| }; | ||||
| </style> | ||||
| </head> | ||||
| <body> | ||||
| <pre> | ||||
| <b><a href="http://sheetjs.com">SheetJS + VueJS3 demo</a></b> | ||||
| 
 | ||||
| This demo shows a sample Vue component "html-preview" that: | ||||
| - displays a file input that accepts a spreadsheet file | ||||
| - draws the first worksheet of a submitted file as HTML | ||||
| - presents an export button to generate XLSX files | ||||
| 
 | ||||
| <a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a> | ||||
| </pre> | ||||
| <script type="text/javascript"> | ||||
|   var _gaq = _gaq || []; | ||||
|   _gaq.push(['_setAccount', 'UA-36810333-1']); | ||||
|   _gaq.push(['_trackPageview']); | ||||
| 
 | ||||
|   (function() { | ||||
|     var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | ||||
|     ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | ||||
|     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | ||||
|   })(); | ||||
| </script> | ||||
| 
 | ||||
| <div id="app"> | ||||
|   <html-preview></html-preview> | ||||
| </div> | ||||
| 
 | ||||
| <script lang="javascript"> | ||||
| if(Vue.component) var app = new Vue({ el: '#app' }); | ||||
| else app.mount('#app'); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
							
								
								
									
										142
									
								
								docz/static/xspreadsheet/index.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										142
									
								
								docz/static/xspreadsheet/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,142 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- sheetjs (C) SheetJS http://sheetjs.com --> | ||||
| <!-- vim: set ts=2: --> | ||||
| <html> | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||||
| <title>SheetJS + x-spreadsheet Live Demo</title> | ||||
| <style> | ||||
| #drop{ | ||||
|   border:2px dashed #bbb; | ||||
|   -moz-border-radius:5px; | ||||
|   -webkit-border-radius:5px; | ||||
|   border-radius:5px; | ||||
|   padding:25px; | ||||
|   text-align:center; | ||||
|   font:20pt bold,"Vollkorn";color:#bbb | ||||
| } | ||||
| #b64data{ | ||||
|   width:100%; | ||||
| } | ||||
| a { text-decoration: none } | ||||
| </style> | ||||
| <!-- x-spreadsheet stylesheet --> | ||||
| <link rel="stylesheet" href="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.css"/> | ||||
| </head> | ||||
| <body> | ||||
| <pre> | ||||
| <b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b> | ||||
| 
 | ||||
| <a href="https://github.com/myliang/x-spreadsheet">x-spreadsheet component library</a> | ||||
| 
 | ||||
| <a href="https://github.com/SheetJS/sheetjs">Source Code Repo</a> | ||||
| <a href="https://github.com/SheetJS/sheetjs/issues">Issues?  Something look weird?  Click here and report an issue</a> | ||||
| 
 | ||||
| <div id="drop">Drop a spreadsheet file here to see sheet data</div> | ||||
| <input type="file" name="xlfile" id="xlf" /> ... or click here to select a file | ||||
| <textarea id="b64data">... or paste a base64-encoding here</textarea> | ||||
| </pre> | ||||
| <p><input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();"></p> | ||||
| <div id="htmlout"></div> | ||||
| <br /> | ||||
| <script src="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.js"></script> | ||||
| <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script> | ||||
| <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script> | ||||
| <script src="https://cdn.sheetjs.com/xspreadsheet/xlsxspread.min.js"></script> | ||||
| <script> | ||||
| /*jshint browser:true */ | ||||
| /* eslint-env browser */ | ||||
| /* eslint no-use-before-define:0 */ | ||||
| /*global Uint8Array, Uint16Array, ArrayBuffer */ | ||||
| /*global XLSX */ | ||||
| 
 | ||||
| var HTMLOUT = document.getElementById('htmlout'); | ||||
| var xspr = x_spreadsheet(HTMLOUT); | ||||
| HTMLOUT.style.height = (window.innerHeight - 400) + "px"; | ||||
| HTMLOUT.style.width = (window.innerWidth - 50) + "px"; | ||||
| 
 | ||||
| var process_wb = (function() { | ||||
|   var XPORT = document.getElementById('xport'); | ||||
| 
 | ||||
|   return function process_wb(wb) { | ||||
|     /* convert to x-spreadsheet form */ | ||||
|     var data = stox(wb); | ||||
| 
 | ||||
|     /* update x-spreadsheet */ | ||||
|     xspr.loadData(data); | ||||
|     XPORT.disabled = false; | ||||
| 
 | ||||
|     if(typeof console !== 'undefined') console.log("output", new Date()); | ||||
|   }; | ||||
| })(); | ||||
| 
 | ||||
| var do_file = (function() { | ||||
|   return function do_file(files) { | ||||
|     var f = files[0]; | ||||
|     var reader = new FileReader(); | ||||
|     reader.onload = function(e) { | ||||
|       if(typeof console !== 'undefined') console.log("onload", new Date()); | ||||
|       var data = e.target.result; | ||||
|       process_wb(XLSX.read(data)); | ||||
|     }; | ||||
|     reader.readAsArrayBuffer(f); | ||||
|   }; | ||||
| })(); | ||||
| 
 | ||||
| (function() { | ||||
|   var drop = document.getElementById('drop'); | ||||
|   if(!drop.addEventListener) return; | ||||
| 
 | ||||
|   function handleDrop(e) { | ||||
|     e.stopPropagation(); | ||||
|     e.preventDefault(); | ||||
|     do_file(e.dataTransfer.files); | ||||
|   } | ||||
| 
 | ||||
|   function handleDragover(e) { | ||||
|     e.stopPropagation(); | ||||
|     e.preventDefault(); | ||||
|     e.dataTransfer.dropEffect = 'copy'; | ||||
|   } | ||||
| 
 | ||||
|   drop.addEventListener('dragenter', handleDragover, false); | ||||
|   drop.addEventListener('dragover', handleDragover, false); | ||||
|   drop.addEventListener('drop', handleDrop, false); | ||||
| })(); | ||||
| 
 | ||||
| (function() { | ||||
|   var xlf = document.getElementById('xlf'); | ||||
|   if(!xlf.addEventListener) return; | ||||
|   function handleFile(e) { do_file(e.target.files); } | ||||
|   xlf.addEventListener('change', handleFile, false); | ||||
| })(); | ||||
| 
 | ||||
| (function() { | ||||
|   try { | ||||
|     fetch("https://sheetjs.com/pres.numbers") | ||||
|       .then(function(res) { return res.arrayBuffer(); }) | ||||
|       .then(function(ab) { process_wb(XLSX.read(ab)); }); | ||||
|   } catch(e) {} | ||||
| })(); | ||||
| 
 | ||||
| function export_xlsx() { | ||||
|   var new_wb = xtos(xspr.getData()); | ||||
| 
 | ||||
|   /* write file and trigger a download */ | ||||
|   XLSX.writeFile(new_wb, 'sheetjs.xlsx', {}); | ||||
| } | ||||
| </script> | ||||
| <script type="text/javascript"> | ||||
| /* eslint no-use-before-define:0 */ | ||||
|   var _gaq = _gaq || []; | ||||
|   _gaq.push(['_setAccount', 'UA-36810333-1']); | ||||
|   _gaq.push(['_trackPageview']); | ||||
| 
 | ||||
|   (function() { | ||||
|     var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | ||||
|     ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | ||||
|     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | ||||
|   })(); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user