diff --git a/.npmignore b/.npmignore index 07db409..a76ea5c 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,6 @@ +.DS_Store *.log .git node_modules -docs +doc examples diff --git a/README.md b/README.md index e01c616..a32ba0a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -# Vue2 Datatable +# vue2-datatable-component [![npm version][npm-v-img]][npm-url] [![npm download][npm-dl-img]][npm-url] -> The Best Datatable for Vue.js 2.x which never sucks +> The best Datatable for Vue.js 2.x which never sucks > `npm i -S vue2-datatable-component` -[Documentation](https://OneWayTech.github.io/vue2-datatable/docs/_book) | +[Documentation](https://OneWayTech.github.io/vue2-datatable/doc) | [Online examples](https://OneWayTech.github.io/vue2-datatable/examples/dist) [npm-url]: https://www.npmjs.com/package/vue2-datatable-component diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..999eeee --- /dev/null +++ b/doc/README.md @@ -0,0 +1,4 @@ +> Choose a language · 请选择语言 + + - [English](en/) + - [中文](zh-cn/) diff --git a/doc/_coverpage.md b/doc/_coverpage.md new file mode 100644 index 0000000..480df65 --- /dev/null +++ b/doc/_coverpage.md @@ -0,0 +1,6 @@ +# vue2-datatable-component + +> The best Datatable for Vue.js 2.x which never sucks + +[GitHub](https://github.com/OneWayTech/vue2-datatable) +[Online examples](https://onewaytech.github.io/vue2-datatable/examples/dist) diff --git a/doc/_images/structure.png b/doc/_images/structure.png new file mode 100644 index 0000000..a574218 Binary files /dev/null and b/doc/_images/structure.png differ diff --git a/doc/_sidebar.md b/doc/_sidebar.md new file mode 100644 index 0000000..83dad6e --- /dev/null +++ b/doc/_sidebar.md @@ -0,0 +1,3 @@ +- Languages · 语言 + - [English](en/) + - [中文](zh-cn/) diff --git a/docs/en/DIY.md b/doc/en/DIY.md similarity index 100% rename from docs/en/DIY.md rename to doc/en/DIY.md diff --git a/doc/en/README.md b/doc/en/README.md new file mode 100644 index 0000000..d9fdc13 --- /dev/null +++ b/doc/en/README.md @@ -0,0 +1,20 @@ +# § Summary + +> This Datatable is only for Vue 2.x. +> But you can downgrade it according to [Migration from Vue 1.x](https://vuejs.org/v2/guide/migration.html). +> (In most of the time, you just have to replace `ref / key / `) + +There are plenty of open-source Datatables, but none of them could meet all the scenarios. +(if there is, this project has no meanings at all) + +This documentation is dedicated to letting you comprehend the design and the source code. +Under this premise, you could build the most suitable Datatable for your own scenario. + +The dependencies of this project are shown as below: + +* BootStrap 3.x + Font Awesome 4.x(must available globally) +* [lodash.orderBy](https://lodash.com/docs/4.17.4#orderBy) +* [replace-with](https://github.com/kenberkeley/replace-with) + +P.S. *BootStrap* and *Font Awesome* can be replaced with other popular libraries. +(It seems to me that you just have to replace some classes / styles) diff --git a/doc/en/_sidebar.md b/doc/en/_sidebar.md new file mode 100644 index 0000000..772601e --- /dev/null +++ b/doc/en/_sidebar.md @@ -0,0 +1,15 @@ +- [Summary](en/README) +- [Preparation](en/preparation) +- [Getting started](en/getting-started) +- [Details (click me)](en/details/README) + - [`props` of Datatable](en/details/datatable-props) + - [`:columns`](en/details/props-columns) + - [`:data`](en/details/props-data) + - [`:query`](en/details/props-query) + - [`:selection`](en/details/props-selection) + - [`:xprops`](en/details/props-xprops) + - [Dynamic Components](en/details/dynamic-comps) +- [I18N](en/i18n) +- [DIY](en/DIY) +- [Q & A (issues)](https://github.com/OneWayTech/vue2-datatable/issues) +- [Changelog (releases)](https://github.com/OneWayTech/vue2-datatable/releases) diff --git a/doc/en/details/README.md b/doc/en/details/README.md new file mode 100644 index 0000000..de3eaa4 --- /dev/null +++ b/doc/en/details/README.md @@ -0,0 +1,32 @@ +# § Details + +It would be better for you to understand the structure of this Datatable before the details. + +The source tree [`lib/`](https://github.com/OneWayTech/vue2-datatable/tree/master/lib) is shown as below: + +``` +lib/ + ├─ HeaderSettings/ + │   ├─ ColumnGroup.vue + │   └─ index.vue + ├── MainTable + │   ├─ _SCROLLBAR_WIDTH.js + │   ├─ _syncScroll.js + │   ├─ HeadSort.vue + │   ├─ index.vue + │   ├─ MultiSelect.vue + │   ├─ TableBody.vue + │   ├─ TableFooter.vue + │   ├─ TableFrame.vue + │   └─ TableHeader.vue + ├─ index.vue + ├─ LimitSelect.vue + ├─ Pagination.vue + └─ props.mixin.js +``` + +Here is the illustration for the tree above, which is captured from the advanced example (source: [`examples/src/Advanced/index.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/examples/src/Advanced/index.vue), demo: [examples#advanced](https://OneWayTech.github.io/vue2-datatable/examples/dist#advanced)): + + + Structure + diff --git a/doc/en/details/datatable-props.md b/doc/en/details/datatable-props.md new file mode 100644 index 0000000..fe67fcb --- /dev/null +++ b/doc/en/details/datatable-props.md @@ -0,0 +1,33 @@ +# § `props` of Datatable + +> Source: [`lib/props.mixin.js`](https://github.com/OneWayTech/vue2-datatable/blob/master/lib/props.mixin.js) + +| prop | Desc | Type | Optional values | Default value | Required | +|---|---|---|---|---|---| +| columns | Defination of columns | Array | - | - | Y | +| data | Data of the current page (rows) | Array | - | - | Y | +| total | Total number of the records | Number | - | - | Y | +| query | Query object | Object | - | - | Y | +| selection | Container for multi-select | Array | - | - | N | +| summary | Summary row | Object | - | - | N | +| xprops | Carrier for extra props passed to dynamic components | Object | - | - | N | +| HeaderSettings | Whether to render `HeaderSettings` | Boolean | true / false | true | N | +| Pagination | Whether to render pagination relevant | Boolean | true / false | true | N | +| tbl-class | Classes for `` | String / Object / Array | - | - | N | +| tbl-style | Inline styles for `
` | String / Object / Array | - | - | N | +| fixHeaderAndSetBodyHeight | (Just as its name implies) | Number | - | - | N | +| support-backup | Whether to enable backup of `HeaderSettings` | Boolean | true / false | false | N | +| support-nested | Whether to enable `nested components` feature (`accordion` mode is available) | Boolean / String | true / false / 'accordion' | false | N | + +> The advanced example (source: [`examples/src/Advanced/index.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/examples/src/Advanced/index.vue), demo: [examples#advanced](https://OneWayTech.github.io/vue2-datatable/examples/dist#advanced)) +> almost covers all the usages, which is highly recommended to study and imitate. + +In the following sections, these props would be elaborated: + +* `columns` +* `data` +* `query` +* `selection` +* `summary` +* `xprops` +* Dynamic components(`thComp / tdComp / nested component`) diff --git a/docs/_book/en/detailed/dynamic-comps.md b/doc/en/details/dynamic-comps.md similarity index 62% rename from docs/_book/en/detailed/dynamic-comps.md rename to doc/en/details/dynamic-comps.md index 64e7bb4..90d3807 100644 --- a/docs/_book/en/detailed/dynamic-comps.md +++ b/doc/en/details/dynamic-comps.md @@ -1,22 +1,23 @@ # § Dynamic Components(`thComp / tdComp / nested component`) -> The following code is excerpted from the source [`lib/index.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/lib/index.vue) - ## ⊙ `thComp` +> Source: [`lib/MainTable/TableHeader.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/lib/MainTable/TableHeader.vue) + ```html - - component (thComp) --> + ``` | prop | Desc | Type | -|-----------|------------------------|--------------------| +|---|---|---| | column | Defination of column | Object | | field | Field name | String / undefined | | title | Displayed title | String / undefined | @@ -24,20 +25,22 @@ ## ⊙ `tdComp` +> Source: [`lib/MainTable/TableBody.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/lib/MainTable/TableBody.vue) + ```html - - component (tdComp) --> + ``` | prop | Desc | Type | -|-----------|------------------------|--------------------| +|---|---|---| | row | Current row | Object | | field | Field name | String / undefined | | value | Value | Any | @@ -46,6 +49,8 @@ ## ⊙ `nested component` +> Source: [`lib/MainTable/TableBody.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/lib/MainTable/TableBody.vue) + ```html ` | String | - | - | N | +| thStyle | Inline styles for `
` | Object | - | - | N | +| thComp | Name of dynamic component for `` | String | - | - | N | +| tdClass | Classes for `` | String | - | - | N | +| tdStyle | Inline styles for `` | Object | - | - | N | +| tdComp | Name of dynamic component for `` | String | - | - | N | diff --git a/doc/en/details/props-data.md b/doc/en/details/props-data.md new file mode 100644 index 0000000..6fd9def --- /dev/null +++ b/doc/en/details/props-data.md @@ -0,0 +1,91 @@ +# `:data` + +> In a more semantic way, it should be named `rows`. +> However, most of the popular Datatables prefer `data`, which should be complied with. + +Normally, it's not necessary to talk about this prop (it's too simple). +But this Datatable supports `nested components` feature by performing magic on it. + +It would be more direct to excerpt `watch:data` from the source code ([`lib/index.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/lib/index.vue)) to see how it works: + +```js +watch: { + data: { + handler (data) { + const { supportNested } = this + // support nested components feature with extra magic + if (supportNested) { + data.forEach(item => { + if (!item.__nested__) { + this.$set(item, '__nested__', { + comp: '', // name of the current nested component + visible: false, + $toggle (comp, visible) { + switch (arguments.length) { + case 0: + this.visible = !this.visible + break + case 1: + switch (typeof comp) { + case 'boolean': + this.visible = comp + break + case 'string': + this.comp = comp + this.visible = !this.visible + break + } + break + case 2: + this.comp = comp + this.visible = visible + break + } + } + }) + // omit the implementation of accordion... + Object.defineProperty(item, '__nested__', { enumerable: false }) + } + }) + } + }, + immediate: true + } +} +``` + +According to the above, an **unenumerable** property `__nested__` is `$set` in every item (row) of data (rows), which includes three properties: + +| Attr | Desc | Type | Optional values / usages | Default value | +|---|---|---|---|---| +| comp | Name of the current nested component | String | - | '' | +| visible | Is the nested component visible | Boolean | true / false | false | +| $toggle | A convenient API to control `comp` and `visible` | Function | `$toggle(comp)` / `$toggle(visible)` / `$toggle(comp, visible)` | - | + +In the source template, `__nested__` would be passed to the related `tdComp` and `nested components`: + +```html + + + + + + + +``` + +By doing all these, we can control the `nested component` by `props.nested.$toggle` within the corresponding dynamic components. +(Of cource, you can manipulate `props.row.__nested__` directly, which is the same thing but more verbose) + +> In the advanced example, component [`Opt`](https://github.com/OneWayTech/vue2-datatable/blob/master/examples/src/Advanced/comps/td-Opt.vue) makes a full use of `props.nested`, which is highly recommended to study and imitate. diff --git a/doc/en/details/props-query.md b/doc/en/details/props-query.md new file mode 100644 index 0000000..c4caa09 --- /dev/null +++ b/doc/en/details/props-query.md @@ -0,0 +1,90 @@ +# `:query` + +Let's see how this Datatable initializes `query` (source: `created` hook in [`lib/index.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/lib/index.vue)): + +```js +created () { + // init query (make all the properties observable by using `$set`) + const q = { limit: 10, offset: 0, sort: '', order: '', ...this.query } + Object.keys(q).forEach(key => { this.$set(this.query, key, q[key]) }) +} +``` + +> According to the above, `query` will change immediately. +> That's why `immediate: true` is not added in `watch:query` (but `deep: true` is required). + +Normally, you just have to pass an empty object `{}`. +If there are any other query conditions (such as `keyword`), you should: + 1. **Either:** initially passing `{ keyword: '' }` (recommended) + 2. **Or:** manually `this.$set(this.query, 'keyword', '')` with [`Vue.set / $vm.$set`](https://vuejs.org/v2/api/#Vue-set) + +> Both of the methods above are used in the advanced example. +> They both have the same purpose: make the extra query conditions [reactive](https://vuejs.org/v2/guide/reactivity.html)! +> (Method 2 can refer to `methods.search` in [`examples/src/Advanced/comps/th-Filter.vue`](https://github.com/OneWayTech/vue2-datatable/blob/master/examples/src/Advanced/comps/th-Filter.vue)) +> +> Tips: If you are using `Ajax - GET`, don't forget to use [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) to escape some special values (such as URLs, etc) + +*** + +#### ⊙ Extention + +Now we have a very common scenario: remain the query conditions after the full page reload. +The most common solution is **synchronizing `query` with the URL query**. + +Here is an example: + +```html + + +``` + +> Q: when does `watch` need `deep: true`? +> A: generally speaking, only two cases included: +> +> 1. an object which is no a computed property +> 2. a nested array which you want to `watch` deeply +> (e.g. `[{ id: 1, name: 'Ken' }, { id: 2, name: 'Berkeley' }]`) +> +> For example, `$route.query` is an object, but it's also a computed property, so `deep: true` is unnecessary diff --git a/doc/en/details/props-selection.md b/doc/en/details/props-selection.md new file mode 100644 index 0000000..b1e264a --- /dev/null +++ b/doc/en/details/props-selection.md @@ -0,0 +1,30 @@ +# `:selection` + +Normally, you just have to pass an empty array `[]`. + +Select the first row in programmatic way: + +```js +this.selection = [ this.data[0] ] +``` + +If you want all the rows selected by default, no problem: + +```js +methods: { + handleQueryChange () { + mockData(this.query).then(({ rows, total, summary }) => { + this.data = rows + this.total = total + this.summary = summary + + this.$nextTick(() => { + this.selection = [...this.data] // that's it! + }) + }) + } +} +``` + +!> Attention: **DO NOT USE `this.selection = this.data`** for selecting all. +Since they share the same reference, any deselection would clear the whole `data`. diff --git a/doc/en/details/props-xprops.md b/doc/en/details/props-xprops.md new file mode 100644 index 0000000..7982604 --- /dev/null +++ b/doc/en/details/props-xprops.md @@ -0,0 +1,79 @@ +# `:xprops` + +`xprops`, means e**x**tra props. + +This Datatable implements `thComp / tdComp / nested component` features with [dynamic components](https://vuejs.org/v2/guide/components.html#Dynamic-Components). +However, various scenarios would be accompanied with various extra props. +As a result, the source template of our Datatable may evolve into: + +```html + + +``` + +For the sake of keeping the source template clean, `xprops` is introduced as the carrier. + +*** + +#### ⊙ Extention + +The most practical usage for `xprops` is carrying an exclusive [eventbus](https://vuejs.org/v2/guide/components.html#Non-Parent-Child-Communication) which only for the current Datatable instance. +Henceforth, no more namespace problems. + +Try with the basic example: + +```html +