├── .all-contributorsrc ├── .babelrc.js ├── .editorconfig ├── .eslintrc.js ├── .github └── badge.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .stylelintrc ├── .travis.yml ├── LICENSE ├── README-zh.md ├── README.md ├── build.sh ├── build └── rollup.config.js ├── docs ├── basic.md ├── before-confirm.md ├── collapsable.md ├── custom-query.md ├── default-expanded-keys.md ├── drag.md ├── dynamic-url.md ├── extra-buttons-type.md ├── extra-buttons.md ├── extra-params.md ├── faq.md ├── has-header.md ├── on-new-edit-delete.md ├── show-checkbox.md ├── show-filter.md ├── slot-node-label.md └── tree-attrs.md ├── notify.sh ├── package.json ├── src ├── el-data-tree.d.ts ├── el-data-tree.md ├── el-data-tree.vue ├── icons │ └── chevron-left.vue ├── index.js └── styles │ └── collapsable.less ├── styleguide.config.js ├── styleguide └── global.requires.js ├── test ├── index.test.js └── sum.js └── yarn.lock /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "el-data-tree", 3 | "projectOwner": "FEMessage", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": false, 11 | "commitConvention": "angular", 12 | "contributors": [ 13 | { 14 | "login": "Alvin-Liu", 15 | "name": "Alvin", 16 | "avatar_url": "https://avatars0.githubusercontent.com/u/11909145?v=4", 17 | "profile": "https://github.com/Alvin-Liu", 18 | "contributions": [ 19 | "code", 20 | "doc", 21 | "example" 22 | ] 23 | }, 24 | { 25 | "login": "levy9527", 26 | "name": "levy", 27 | "avatar_url": "https://avatars3.githubusercontent.com/u/9384365?v=4", 28 | "profile": "https://github.com/levy9527/blog", 29 | "contributions": [ 30 | "review", 31 | "translation" 32 | ] 33 | }, 34 | { 35 | "login": "xrr2016", 36 | "name": "Cold Stone", 37 | "avatar_url": "https://avatars1.githubusercontent.com/u/18013127?v=4", 38 | "profile": "https://coldstone.fun", 39 | "contributions": [ 40 | "code" 41 | ] 42 | }, 43 | { 44 | "login": "evillt", 45 | "name": "EVILLT", 46 | "avatar_url": "https://avatars3.githubusercontent.com/u/19513289?v=4", 47 | "profile": "https://evila.me", 48 | "contributions": [ 49 | "code", 50 | "maintenance" 51 | ] 52 | }, 53 | { 54 | "login": "donaldshen", 55 | "name": "Donald Shen", 56 | "avatar_url": "https://avatars3.githubusercontent.com/u/19591950?v=4", 57 | "profile": "https://donaldshen.github.io/portfolio", 58 | "contributions": [ 59 | "doc", 60 | "maintenance" 61 | ] 62 | }, 63 | { 64 | "login": "colmugx", 65 | "name": "ColMugX", 66 | "avatar_url": "https://avatars1.githubusercontent.com/u/21327913?v=4", 67 | "profile": "https://colmugx.github.io", 68 | "contributions": [ 69 | "maintenance" 70 | ] 71 | }, 72 | { 73 | "login": "OuZuYu", 74 | "name": "OuZuYu", 75 | "avatar_url": "https://avatars3.githubusercontent.com/u/26338853?v=4", 76 | "profile": "http://67.216.223.155/resume/", 77 | "contributions": [ 78 | "bug" 79 | ] 80 | } 81 | ], 82 | "contributorsPerLine": 7 83 | } 84 | -------------------------------------------------------------------------------- /.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = api => { 2 | return { 3 | presets: [['@babel/env', {modules: api.env('test') ? 'commonjs' : false}]], 4 | plugins: [ 5 | [ 6 | '@babel/transform-runtime', 7 | { 8 | regenerator: true 9 | } 10 | ] 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint' 9 | }, 10 | extends: [ 11 | 'eslint:recommended', 12 | 'plugin:jest/recommended', 13 | 'plugin:vue/recommended', 14 | 'plugin:prettier/recommended', 15 | 'prettier/vue' 16 | ], 17 | plugins: ['vue', 'prettier'], 18 | rules: { 19 | 'no-console': [ 20 | 'error', 21 | { 22 | allow: ['warn', 'error'] 23 | } 24 | ], 25 | 'no-debugger': 'error', 26 | 'prettier/prettier': 'error' 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/badge.yml: -------------------------------------------------------------------------------- 1 | types: 2 | feat: 'enhancement' 3 | fix: 'bug' 4 | docs: 'documentation' 5 | refactor: 'refactor' 6 | test: 'test' 7 | perf: 'performance' 8 | chore: 9 | deps: 'dependencies' 10 | default: 'chore' 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | dist 7 | docs/build 8 | docs/index.html 9 | 10 | # Editor directories and files 11 | .idea 12 | .vscode 13 | *.suo 14 | *.ntvs* 15 | *.njsproj 16 | *.sln 17 | .env 18 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | docs 2 | dist 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | semi: false 2 | singleQuote: true 3 | bracketSpacing: false 4 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "no-empty-source": null 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | only: 3 | - master 4 | language: node_js 5 | node_js: 6 | - lts/* 7 | git: 8 | depth: 3 9 | install: 10 | - yarn --frozen-lockfile 11 | - yarn test 12 | script: 13 | - ./build.sh 14 | after_script: 15 | - ./notify.sh 16 | cache: yarn 17 | deploy: 18 | - provider: pages 19 | local-dir: docs 20 | github-token: $GITHUB_TOKEN 21 | skip-cleanup: true 22 | keep-history: true 23 | - provider: npm 24 | email: levy9527@qq.com 25 | api_key: $NPM_TOKEN 26 | skip-cleanup: true 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 FEMessage 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-zh.md: -------------------------------------------------------------------------------- 1 | # el-data-tree 2 | 3 | [![Build Status](https://travis-ci.com/FEMessage/el-data-tree.svg?branch=master)](https://travis-ci.com/FEMessage/el-data-tree) 4 | [![NPM Download](https://img.shields.io/npm/dm/@femessage/el-data-tree.svg)](https://www.npmjs.com/package/@femessage/el-data-tree) 5 | [![NPM Version](https://img.shields.io/npm/v/@femessage/el-data-tree.svg)](https://www.npmjs.com/package/@femessage/el-data-tree) 6 | [![NPM License](https://img.shields.io/npm/l/@femessage/el-data-tree.svg)](https://github.com/FEMessage/el-data-tree/blob/master/LICENSE) 7 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/FEMessage/el-data-tree/pulls) 8 | [![Automated Release Notes by gren](https://img.shields.io/badge/%F0%9F%A4%96-release%20notes-00B2EE.svg)](https://github-tools.github.io/github-release-notes/) 9 | 10 | 使用`axios`自动发送请求,支持筛选, 自定义操作列, 让 RESTful 风格的 CRUD 更简单 👏 11 | 12 | ![el-data-tree-crud.gif](https://i.loli.net/2019/11/14/xd3mkSXasu1oe2n.gif) 13 | 14 | ## Table of Contents 15 | 16 | - [Introduction](#introduction) 17 | - [CRUD](#crud) 18 | - [Feature](#feature) 19 | - [Demo](#demo) 20 | - [Pre Install](#pre-install) 21 | - [Install](#install) 22 | - [Quick Start](#quick-start) 23 | - [Global Register Component](#global-register-component) 24 | - [Template](#template) 25 | - [Contributors](#contributors) 26 | - [License](#license) 27 | 28 | ## Introduction 29 | 30 | ### CRUD 31 | 32 | el-data-tree 就是为了解决业务问题而生的,故而封装了 CRUD 的逻辑在里面。 33 | 34 | 以用户接口示例,设其相对路径为: 35 | 36 | ```sh 37 | /api/v1/users 38 | ``` 39 | 40 | 则其 restful CRUD 接口如下: 41 | 42 | - 查询 43 | 44 | ```sh 45 | GET /api/v1/users?type=1 46 | ``` 47 | 48 | - 新增 49 | 50 | ```sh 51 | POST /api/v1/users 52 | ``` 53 | 54 | - 修改(编辑) 55 | 56 | ```sh 57 | PUT /api/v1/users/:id 58 | ``` 59 | 60 | - 删除 61 | 62 | ```sh 63 | DELETE /api/v1/users/:id 64 | ``` 65 | 66 | 则只需要使用以下代码,即可完成 CRUD 功能 67 | 68 | ```vue 69 | 72 | ``` 73 | 74 | ```js 75 | 105 | ``` 106 | 107 | 效果如下: 108 | 109 | - 查询 110 | 111 | ![el-data-tree-search.png](https://i.loli.net/2019/11/14/onYZzKgP8lScEyi.png) 112 | 113 | - 新增 114 | 115 | ![el-data-tree-add.png](https://i.loli.net/2019/11/14/NKjsl2Bf5ZQ39pb.png) 116 | 117 | - 修改 118 | 119 | ![el-data-tree-modify.png](https://i.loli.net/2019/11/14/QG2hpXIbrB1lZNv.png) 120 | 121 | - 删除 122 | 123 | ![el-data-tree-delete.png](https://i.loli.net/2019/11/14/t7JmLonjlpRVq9K.png) 124 | 125 | [⬆ Back to Top](#table-of-contents) 126 | 127 | ## Feature 128 | 129 | - 只需进行 json 配置,即可实现 restful 风格的 CRUD 四个接口的对接 130 | - 可扩展自定义菜单栏,以及自定义操作函数 131 | - 默认保存展开状态,新增、删除、编辑不丢失该状态 132 | - 优化节点勾选方法 133 | 134 | [⬆ Back to Top](#table-of-contents) 135 | 136 | ## Demo 137 | 138 | - [doc and online demo](https://femessage.github.io/el-data-tree/) 139 | 140 | [⬆ Back to Top](#table-of-contents) 141 | 142 | ## Pre Install 143 | 144 | this component peerDependencies on [element-ui](http://element.eleme.io/#/zh-CN/component/tree) and [@femessage/el-form-renderer](https://github.com/FEMessage/el-form-renderer) and [axios](https://github.com/axios/axios) 145 | 146 | make sure you have installed in your project 147 | 148 | ```sh 149 | yarn add element-ui @femessage/el-form-renderer axios 150 | ``` 151 | 152 | if you want to develop the component on your localhost, you should install with -P 153 | 154 | ```sh 155 | yarn add element-ui @femessage/el-form-renderer axios -P 156 | ``` 157 | 158 | [⬆ Back to Top](#table-of-contents) 159 | 160 | ## Install 161 | 162 | encourage using [yarn](https://yarnpkg.com/en/docs/install#mac-stable) to install 163 | 164 | ```sh 165 | yarn add @femessage/el-data-tree 166 | ``` 167 | 168 | [⬆ Back to Top](#table-of-contents) 169 | 170 | ## Quick Start 171 | 172 | ### Global Register Component 173 | 174 | this is for minification reason: in this way building your app, 175 | 176 | webpack or other bundler just bundle the dependencies into one vendor for all pages which using this component, 177 | 178 | instead of one vendor for one page 179 | 180 | ```js 181 | import Vue from 'vue' 182 | 183 | // register component and loading directive 184 | import ElDataTree from '@femessage/el-data-tree' 185 | import ElFormRenderer from '@femessage/el-form-renderer' 186 | import { 187 | Button, 188 | Dialog, 189 | Dropdown, 190 | DropdownMenu, 191 | DropdownItem, 192 | Form, 193 | FormItem, 194 | Input, 195 | Loading, 196 | Tree, 197 | MessageBox, 198 | Message 199 | } from 'element-ui' 200 | 201 | Vue.use(Button) 202 | Vue.use(Dialog) 203 | Vue.use(Dropdown) 204 | Vue.use(DropdownMenu) 205 | Vue.use(DropdownItem) 206 | Vue.use(Form) 207 | Vue.use(FormItem) 208 | Vue.use(Input) 209 | Vue.use(Loading.directive) 210 | Vue.use(Tree) 211 | Vue.component('el-form-renderer', ElFormRenderer) 212 | Vue.component('el-data-tree', ElDataTree) 213 | 214 | // to show confirm before delete 215 | Vue.prototype.$confirm = MessageBox.confirm 216 | // if the tree component cannot access `this.$axios`, it cannot send request 217 | import axios from 'axios' 218 | Vue.prototype.$axios = axios 219 | ``` 220 | 221 | [⬆ Back to Top](#table-of-contents) 222 | 223 | ### Template 224 | 225 | ```vue 226 | 229 | ``` 230 | 231 | [⬆ Back to Top](#table-of-contents) 232 | 233 | ## Contributors 234 | 235 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 236 | 237 | 238 | 239 |
Alvin
Alvin

💻 📖 💡
levy
levy

👀 🌍
Cold Stone
Cold Stone

💻
EVILLT
EVILLT

💻 🚧
Donald Shen
Donald Shen

📖 🚧
ColMugX
ColMugX

🚧
OuZuYu
OuZuYu

🐛
240 | 241 | 242 | 243 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 244 | 245 | [⬆ Back to Top](#table-of-contents) 246 | 247 | ## License 248 | 249 | [MIT](./LICENSE) 250 | 251 | [⬆ Back to Top](#table-of-contents) 252 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # el-data-tree 2 | 3 | [![Build Status](https://travis-ci.com/FEMessage/el-data-tree.svg?branch=master)](https://travis-ci.com/FEMessage/el-data-tree) 4 | [![NPM Download](https://img.shields.io/npm/dm/@femessage/el-data-tree.svg)](https://www.npmjs.com/package/@femessage/el-data-tree) 5 | [![NPM Version](https://img.shields.io/npm/v/@femessage/el-data-tree.svg)](https://www.npmjs.com/package/@femessage/el-data-tree) 6 | [![NPM License](https://img.shields.io/npm/l/@femessage/el-data-tree.svg)](https://github.com/FEMessage/el-data-tree/blob/master/LICENSE) 7 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/FEMessage/el-data-tree/pulls) 8 | [![Automated Release Notes by gren](https://img.shields.io/badge/%F0%9F%A4%96-release%20notes-00B2EE.svg)](https://github-tools.github.io/github-release-notes/) 9 | 10 | Use `axios` to automatically send requests, support filtering, customize action columns, and make RESTful CRUD simpler 👏 11 | 12 | ![el-data-tree-crud.gif](https://i.loli.net/2019/11/14/xd3mkSXasu1oe2n.gif) 13 | 14 | [中文文档](./README-zh.md) 15 | 16 | ## Table of Contents 17 | 18 | - [Introduction](#introduction) 19 | - [CRUD](#crud) 20 | - [Feature](#feature) 21 | - [Demo](#demo) 22 | - [Pre Install](#pre-install) 23 | - [Install](#install) 24 | - [Quick Start](#quick-start) 25 | - [Global Register Component](#global-register-component) 26 | - [Template](#template) 27 | - [Contributors](#contributors) 28 | - [License](#license) 29 | 30 | ## Introduction 31 | 32 | ### CRUD 33 | 34 | el-data-tree is created to solve business problems, so CRUD logic is set inside.
For example, to develop `user` api, suppose its relative path like this: 35 | 36 | ```sh 37 | /api/v1/users 38 | ``` 39 | 40 | The restful CRUD api should be: 41 | 42 | - Retrieve 43 | 44 | ```javascript 45 | GET /api/v1/users?type=1 46 | ``` 47 | 48 | - Create 49 | 50 | ```javascript 51 | POST / api / v1 / users 52 | ``` 53 | 54 | - Update 55 | 56 | ```javascript 57 | PUT /api/v1/users/:id 58 | ``` 59 | 60 | - Delete 61 | 62 | ```javascript 63 | DELETE /api/v1/users/:id 64 | ``` 65 | 66 | Then only need to use the following code to complete CRUD functions 67 | 68 | ```html 69 | 72 | ``` 73 | 74 | ```javascript 75 | 105 | ``` 106 | 107 | The results are as follows: 108 | 109 | - Retrieve 110 | 111 | ![el-data-tree-search.png](https://i.loli.net/2019/11/14/onYZzKgP8lScEyi.png) 112 | 113 | - Create 114 | 115 | ![el-data-tree-add.png](https://i.loli.net/2019/11/14/NKjsl2Bf5ZQ39pb.png) 116 | 117 | - Update 118 | 119 | ![el-data-tree-modify.png](https://i.loli.net/2019/11/14/QG2hpXIbrB1lZNv.png) 120 | 121 | - Delete 122 | 123 | ![el-data-tree-delete.png](https://i.loli.net/2019/11/14/t7JmLonjlpRVq9K.png) 124 | 125 | [⬆ Back to Top](#table-of-contents) 126 | 127 | ## Feature 128 | 129 | - Use configuration to call restful api to complete CRUD functions 130 | - Support custom menu bar, as well as custom action functions 131 | - Save the expandedKeys by default and will not losing the expandedKeys state after calling create/delete/update apis 132 | - Optimized node check method 133 | 134 | [⬆ Back to Top](#table-of-contents) 135 | 136 | ## Demo 137 | 138 | - [doc and online demo](https://femessage.github.io/el-data-tree/) 139 | 140 | [⬆ Back to Top](#table-of-contents) 141 | 142 | ## Pre Install 143 | 144 | This component peerDependencies on [element-ui](http://element.eleme.io/#/zh-CN/component/tree) and [@femessage/el-form-renderer](https://github.com/FEMessage/el-form-renderer) and [axios](https://github.com/axios/axios)
make sure you have installed in your project 145 | 146 | ```sh 147 | yarn add element-ui @femessage/el-form-renderer axios 148 | ``` 149 | 150 | [⬆ Back to Top](#table-of-contents) 151 | 152 | ## Install 153 | 154 | Encourage using [yarn](https://yarnpkg.com/en/docs/install#mac-stable) to install 155 | 156 | ```sh 157 | yarn add @femessage/el-data-tree 158 | ``` 159 | 160 | [⬆ Back to Top](#table-of-contents) 161 | 162 | ## Quick Start 163 | 164 | ### Global Register Component 165 | 166 | This is for minification reason: in this way building your app, webpack or other bundler just bundle the dependencies into one vendor for all pages which using this component, instead of one vendor for one page 167 | 168 | ```javascript 169 | import Vue from 'vue' 170 | // register component and loading directive 171 | import ElDataTree from '@femessage/el-data-tree' 172 | import ElFormRenderer from '@femessage/el-form-renderer' 173 | import { 174 | Button, 175 | Dialog, 176 | Dropdown, 177 | DropdownMenu, 178 | DropdownItem, 179 | Form, 180 | FormItem, 181 | Input, 182 | Loading, 183 | Tree, 184 | MessageBox, 185 | Message 186 | } from 'element-ui' 187 | Vue.use(Button) 188 | Vue.use(Dialog) 189 | Vue.use(Dropdown) 190 | Vue.use(DropdownMenu) 191 | Vue.use(DropdownItem) 192 | Vue.use(Form) 193 | Vue.use(FormItem) 194 | Vue.use(Input) 195 | Vue.use(Loading.directive) 196 | Vue.use(Tree) 197 | Vue.component('el-form-renderer', ElFormRenderer) 198 | Vue.component('el-data-tree', ElDataTree) 199 | // to show confirm before delete 200 | Vue.prototype.$confirm = MessageBox.confirm 201 | // if the tree component cannot access `this.$axios`, it cannot send request 202 | import axios from 'axios' 203 | Vue.prototype.$axios = axios 204 | ``` 205 | 206 | [⬆ Back to Top](#table-of-contents) 207 | 208 | ### Template 209 | 210 | ```vue 211 | 214 | ``` 215 | 216 | [⬆ Back to Top](#table-of-contents) 217 | 218 | ## Contributors 219 | 220 | 221 | 222 |
Alvin
Alvin

💻 📖 💡
levy
levy

👀 🌍
Cold Stone
Cold Stone

💻
EVILLT
EVILLT

💻 🚧
Donald Shen
Donald Shen

📖 🚧
ColMugX
ColMugX

🚧
OuZuYu
OuZuYu

🐛
223 | 224 | 225 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 226 | 227 | [⬆ Back to Top](#table-of-contents) 228 | 229 | ## License 230 | 231 | [MIT](./LICENSE) 232 | 233 | [⬆ Back to Top](#table-of-contents) 234 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | yarn stdver 3 | 4 | yarn build 5 | -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | // rollup.config.js 2 | import vue from 'rollup-plugin-vue' 3 | import babel from 'rollup-plugin-babel' 4 | import commonjs from 'rollup-plugin-commonjs' 5 | import {terser} from 'rollup-plugin-terser' 6 | import minimist from 'minimist' 7 | 8 | const argv = minimist(process.argv.slice(2)) 9 | 10 | const config = { 11 | input: 'src/index.js', 12 | output: { 13 | name: 'ElDataTree', 14 | exports: 'named' 15 | }, 16 | plugins: [ 17 | commonjs(), 18 | vue({ 19 | css: true, 20 | compileTemplate: true 21 | }), 22 | babel({ 23 | runtimeHelpers: true, 24 | exclude: 'node_modules/**' 25 | }) 26 | ] 27 | } 28 | 29 | // Only minify browser (iife) version 30 | if (argv.format === 'iife') { 31 | config.plugins.push(terser()) 32 | } 33 | 34 | export default config 35 | -------------------------------------------------------------------------------- /docs/basic.md: -------------------------------------------------------------------------------- 1 | 基础用法 2 | 3 | ```vue 4 | 7 | 8 | 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/before-confirm.md: -------------------------------------------------------------------------------- 1 | 在新增/修改弹窗点击确认, 并完成表单 form 表单校验后调用,需要返回 Promise. 2 | 如果 resolve, 则会发送新增/修改请求; 如果 reject, 则不会发送新增/修改请求. 3 | 参数: (data, isNew) data 为表单数据, isNew true 表示是新增弹窗, false 为 编辑弹窗 4 | 5 | ```vue 6 | 9 | 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/collapsable.md: -------------------------------------------------------------------------------- 1 | 折叠树 2 | 3 | ```vue 4 | 9 | 10 | 31 | ``` -------------------------------------------------------------------------------- /docs/custom-query.md: -------------------------------------------------------------------------------- 1 | 请求数据时携带的参数 2 | 3 | ```vue 4 | 7 | 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/default-expanded-keys.md: -------------------------------------------------------------------------------- 1 | 支持默认展开 2 | 3 | ```vue 4 | 7 | 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/drag.md: -------------------------------------------------------------------------------- 1 | 拖拽树的节点示例 2 | 3 | ```vue 4 | 7 | 8 | 60 | ``` 61 | 62 | 示例 63 | 64 | ![el-data-tree-drag _1_.gif](https://i.loli.net/2019/11/14/WCvnBc91zs6Rjp8.gif) 65 | -------------------------------------------------------------------------------- /docs/dynamic-url.md: -------------------------------------------------------------------------------- 1 | url可在运行时动态变化 2 | 3 | ```vue 4 | 7 | 8 | 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/extra-buttons-type.md: -------------------------------------------------------------------------------- 1 | 自定义节点菜单(text) 2 | 3 | ```vue 4 | 7 | 8 | 27 | 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/extra-buttons.md: -------------------------------------------------------------------------------- 1 | 可自定义按钮选项 2 | 3 | ```vue 4 | 7 | 8 | 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/extra-params.md: -------------------------------------------------------------------------------- 1 | 新增修改请求携带额外参数 2 | 3 | ```vue 4 | 7 | 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | ## 在 TypeScript 中指定组件的类型 2 | 3 | ```html 4 | 13 | ``` 14 | > 关于更多可用类型请参考:[el-data-tree.d.ts](https://github.com/FEMessage/el-data-tree/blob/dev/src/el-data-tree.d.ts) -------------------------------------------------------------------------------- /docs/has-header.md: -------------------------------------------------------------------------------- 1 | 有标题的用法 2 | 3 | ```vue 4 | 11 | 12 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/on-new-edit-delete.md: -------------------------------------------------------------------------------- 1 | 自定义新增、修改和删除时的方法 2 | 3 | ```vue 4 | 7 | 8 | 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/show-checkbox.md: -------------------------------------------------------------------------------- 1 | 被选中的节点的id会自动同步到checkedKeys以供后续提交。 2 | 3 | ```vue 4 | 17 | 18 | 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/show-filter.md: -------------------------------------------------------------------------------- 1 | 节点过滤 2 | 3 | ```vue 4 | 7 | 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/slot-node-label.md: -------------------------------------------------------------------------------- 1 | 自定义节点文本内容 2 | 3 | ```vue 4 | 13 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/tree-attrs.md: -------------------------------------------------------------------------------- 1 | 支持配置el-tree 2 | 3 | ```vue 4 | 7 | 8 | 25 | ``` 26 | -------------------------------------------------------------------------------- /notify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ "$TRAVIS_TEST_RESULT" != "0" ] 3 | then 4 | echo "build not success, bye" 5 | exit 1 6 | fi 7 | 8 | git remote add github https://$GITHUB_TOKEN@github.com/FEMessage/el-data-tree.git > /dev/null 2>&1 9 | git push github HEAD:master --follow-tags 10 | 11 | GREN_GITHUB_TOKEN=$GITHUB_TOKEN yarn release 12 | 13 | url=https://api.github.com/repos/FEMessage/el-data-tree/releases/latest 14 | resp_tmp_file=resp.tmp 15 | 16 | curl -H "Authorization: token $GITHUB_TOKEN" $url > $resp_tmp_file 17 | 18 | html_url=$(sed -n 5p $resp_tmp_file | sed 's/\"html_url\"://g' | awk -F '"' '{print $2}') 19 | body=$(grep body < $resp_tmp_file | sed 's/\"body\"://g;s/\"//g') 20 | version=$(echo $html_url | awk -F '/' '{print $NF}') 21 | 22 | msg='{"msgtype": "markdown", "markdown": {"title": "el-data-tree更新", "text": "@所有人\n# [el-data-tree('$version')]('$html_url')\n'$body'"}}' 23 | 24 | curl -X POST https://oapi.dingtalk.com/robot/send\?access_token\=$DINGTALK_ROBOT_TOKEN -H 'Content-Type: application/json' -d "$msg" 25 | 26 | rm $resp_tmp_file 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@femessage/el-data-tree", 3 | "version": "0.2.0", 4 | "description": "base on element-ui, makes crud easily", 5 | "author": "https://github.com/FEMessage", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/FEMessage/el-data-tree.git" 10 | }, 11 | "keywords": [ 12 | "vue", 13 | "element-ui", 14 | "tree", 15 | "data-tree", 16 | "element tree" 17 | ], 18 | "files": [ 19 | "src", 20 | "dist", 21 | "yarn.lock" 22 | ], 23 | "main": "dist/el-data-tree.umd.js", 24 | "module": "dist/el-data-tree.esm.js", 25 | "unpkg": "dist/el-data-tree.min.js", 26 | "browser": { 27 | "./sfc": "src/el-data-tree.vue" 28 | }, 29 | "types": "src/el-data-tree.d.ts", 30 | "scripts": { 31 | "dev": "vue-styleguidist server", 32 | "test": "jest", 33 | "doc": "vue-styleguidist build", 34 | "build": "npm run build:unpkg & npm run build:es & npm run build:umd & npm run doc", 35 | "build:umd": "rollup --config build/rollup.config.js --format umd --file dist/el-data-tree.umd.js", 36 | "build:es": "rollup --config build/rollup.config.js --format es --file dist/el-data-tree.esm.js", 37 | "build:unpkg": "rollup --config build/rollup.config.js --format iife --file dist/el-data-tree.min.js", 38 | "stdver": "standard-version -m '[skip ci] chore(release): v%s'", 39 | "lint": "eslint \"**/*.@(js|vue)\" --fix", 40 | "release": "gren release --override" 41 | }, 42 | "dependencies": { 43 | "lodash.get": "^4.4.2" 44 | }, 45 | "devDependencies": { 46 | "@babel/core": "^7.4.3", 47 | "@babel/plugin-transform-runtime": "^7.4.3", 48 | "@babel/preset-env": "^7.4.3", 49 | "@femessage/el-form-renderer": "^1.6.0", 50 | "@femessage/github-release-notes": "^0.19.0", 51 | "@femessage/types": "^1.0.3", 52 | "axios": "^0.18.0", 53 | "babel-eslint": "^10.0.3", 54 | "babel-loader": "^8.0.5", 55 | "css-loader": "^2.1.1", 56 | "element-ui": "2.4.11", 57 | "eslint": "^6.6.0", 58 | "eslint-config-prettier": "^6.5.0", 59 | "eslint-plugin-jest": "^23.0.3", 60 | "eslint-plugin-prettier": "^3.1.1", 61 | "eslint-plugin-vue": "^6.0.1", 62 | "file-loader": "^3.0.1", 63 | "glob": "^7.1.3", 64 | "husky": "1.3.1", 65 | "jest": "^24.8.0", 66 | "less": "^3.11.1", 67 | "less-loader": "^5.0.0", 68 | "lint-staged": "^8.1.0", 69 | "minimist": "^1.2.0", 70 | "prettier": "1.18.2", 71 | "rollup": "^1.9.0", 72 | "rollup-plugin-babel": "^4.3.2", 73 | "rollup-plugin-commonjs": "^9.3.4", 74 | "rollup-plugin-terser": "^4.0.4", 75 | "rollup-plugin-vue": "^4.7.2", 76 | "standard-version": "^6.0.1", 77 | "stylelint": "^9.10.0", 78 | "stylelint-config-standard": "^18.2.0", 79 | "vue": "^2.6.10", 80 | "vue-loader": "^15.7.1", 81 | "vue-styleguidist": "^3.16.3", 82 | "vue-template-compiler": "^2.5.16", 83 | "webpack": "^4.29.6" 84 | }, 85 | "publishConfig": { 86 | "access": "public" 87 | }, 88 | "vue-sfc-cli": "1.10.4", 89 | "engines": { 90 | "node": ">= 4.0.0", 91 | "npm": ">= 3.0.0" 92 | }, 93 | "husky": { 94 | "hooks": { 95 | "pre-commit": "lint-staged", 96 | "post-commit": "git update-index --again" 97 | } 98 | }, 99 | "lint-staged": { 100 | "*.@(md|json)": [ 101 | "prettier --write", 102 | "git add" 103 | ], 104 | "*.js": [ 105 | "eslint --fix", 106 | "prettier --write", 107 | "git add" 108 | ], 109 | "*.vue": [ 110 | "eslint --fix", 111 | "prettier --write", 112 | "stylelint --fix", 113 | "git add" 114 | ] 115 | }, 116 | "gren": "@femessage/grenrc" 117 | } 118 | -------------------------------------------------------------------------------- /src/el-data-tree.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, {VueConstructor, VNode} from 'vue' 2 | 3 | import {Form, Tree} from '@femessage/types/element-ui' 4 | 5 | declare module '@femessage/el-data-tree' { 6 | class FemessageComponent extends Vue { 7 | static install(vue: typeof Vue): void 8 | } 9 | 10 | type CombinedVueInstance< 11 | Instance extends Vue, 12 | Data, 13 | Methods, 14 | Computed, 15 | Props 16 | > = Data & Methods & Computed & Props & Instance 17 | 18 | type ExtendedVue< 19 | Instance extends Vue, 20 | Data, 21 | Methods, 22 | Computed, 23 | Props 24 | > = VueConstructor< 25 | CombinedVueInstance & Vue 26 | > 27 | 28 | type Combined = Data & 29 | Methods & 30 | Computed & 31 | Props 32 | 33 | type ElDataTreeData = { 34 | treeData: any 35 | filterText: string 36 | loading: boolean 37 | dialogTitle: string 38 | dialogVisible: boolean 39 | isNew: boolean 40 | isEdit: boolean 41 | confirmLoading: boolean 42 | row: object 43 | defaultExpandedKeys: any[] 44 | cacheExpandedKeys: any 45 | isCollapsed: boolean 46 | } 47 | 48 | type ElDataTreeMethods = { 49 | fetchData: () => void 50 | 51 | getTree: () => Tree 52 | 53 | updateCheckedKeys: (keys: any[]) => void 54 | } 55 | 56 | type ElDataTreeComputed = {} 57 | 58 | export interface FormContentItem { 59 | id: string 60 | label?: string | VNode 61 | [key: string]: any 62 | } 63 | 64 | export type FormContent = Array 65 | 66 | export type ExtraButtonType = 'text' | 'dropdown' 67 | 68 | export interface ExtraButton { 69 | type: ExtraButtonType 70 | text: string 71 | atClick: (data: any, node: any) => Promise 72 | show: (data: any, node: any) => boolean 73 | } 74 | 75 | // props 全都有默认值,都是可选的 76 | export type ElDataTreeProps = Partial<{ 77 | title: string 78 | hasBorder: boolean 79 | treeAttrs: Partial 80 | url: string 81 | parentKey: string 82 | dataPath: string 83 | showFilter: boolean 84 | checkedKeys: any[] 85 | extraButtons: ExtraButton[] 86 | extraButtonsType: ExtraButtonType 87 | form: FormContent 88 | formAttrs: Partial
89 | extraParams: object 90 | customQuery: object 91 | hasOperation: boolean 92 | hasTitle: boolean 93 | hasHeader: boolean 94 | hasDelete: boolean 95 | hasNew: boolean 96 | hasEdit: boolean 97 | transform: (data: any) => any 98 | onNew: (data: any, row: any) => Promise 99 | onEdit: (data: any, row: any) => Promise 100 | onDelete: (data: any, node: any) => any 101 | beforeConfirm: (data: any, isNew: boolean) => Promise 102 | newText: string 103 | editText: string 104 | deleteText: string 105 | collapsable: boolean 106 | }> 107 | 108 | type ElDataTree = Combined< 109 | ElDataTreeData, 110 | ElDataTreeMethods, 111 | ElDataTreeComputed, 112 | Required 113 | > 114 | 115 | export interface ElDataTreeType extends FemessageComponent, ElDataTree {} 116 | 117 | const ElDataTreeConstruction: ExtendedVue< 118 | Vue, 119 | ElDataTreeData, 120 | ElDataTreeMethods, 121 | ElDataTreeComputed, 122 | Required 123 | > 124 | 125 | export default ElDataTreeConstruction 126 | } 127 | -------------------------------------------------------------------------------- /src/el-data-tree.md: -------------------------------------------------------------------------------- 1 | ## API 补充 2 | 3 | vue-styleguidist 无法提取部分文档内容,详见[官方 issues](https://github.com/vue-styleguidist/vue-styleguidist/issues) 4 | 5 | ### Slots 6 | 7 | | Slot | 描述 | SlotProps | 8 | | ---------- | -------------------- | --------- | 9 | | node-label | 可定制的节点标签内容 | data | 10 | -------------------------------------------------------------------------------- /src/el-data-tree.vue: -------------------------------------------------------------------------------- 1 | 161 | 162 | 750 | 751 | 855 | 856 | 857 | -------------------------------------------------------------------------------- /src/icons/chevron-left.vue: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // Import vue component 2 | import Component from './el-data-tree.vue' 3 | 4 | // `Vue.use` automatically prevents you from using 5 | // the same plugin more than once, 6 | // so calling it multiple times on the same plugin 7 | // will install the plugin only once 8 | Component.install = (Vue, options = {}) => { 9 | Vue.prototype.$elDataTreeOptions = options 10 | Vue.component(Component.name, Component) 11 | } 12 | 13 | // To auto-install when vue is found 14 | let GlobalVue = null 15 | if (typeof window !== 'undefined') { 16 | GlobalVue = window.Vue 17 | } else if (typeof global !== 'undefined') { 18 | GlobalVue = global.Vue 19 | } 20 | if (GlobalVue) { 21 | GlobalVue.use(Component) 22 | } 23 | 24 | // To allow use as module (npm/webpack/etc.) export component 25 | export default Component 26 | 27 | // It's possible to expose named exports when writing components that can 28 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo'; 29 | // export const RollupDemoDirective = component; 30 | -------------------------------------------------------------------------------- /src/styles/collapsable.less: -------------------------------------------------------------------------------- 1 | .el-data-tree { 2 | position: relative; 3 | width: 100%; 4 | 5 | & .el-tree { 6 | background-color: transparent; 7 | } 8 | 9 | & .el-data-tree-main { 10 | transition: 0.3s; 11 | } 12 | 13 | &.is-collapsed { 14 | min-width: 20px; 15 | width: 20px; 16 | background-color: #ebeef5; 17 | cursor: pointer; 18 | 19 | & .collapse-icon { 20 | transform: rotate(180deg); 21 | } 22 | 23 | & .el-data-tree-main { 24 | // 折叠后隐藏所有树节点内容 25 | & .body { 26 | opacity: 0; 27 | } 28 | } 29 | } 30 | 31 | &:hover { 32 | & .collapse-icon-wrapper .collapse-icon { 33 | opacity: 1; 34 | } 35 | } 36 | 37 | & .collapse-icon-wrapper { 38 | @size: 26px; 39 | 40 | position: absolute; 41 | width: @size; 42 | height: @size; 43 | top: @size; 44 | right: 0 - (@size / 2); 45 | 46 | & .collapse-icon { 47 | transition: 0.3s; 48 | width: 100%; 49 | height: 100%; 50 | border-radius: 50%; 51 | box-shadow: 0 0 4px #999; 52 | background-color: #fff; 53 | opacity: 0; 54 | display: flex; 55 | align-items: center; 56 | justify-content: center; 57 | cursor: pointer; 58 | 59 | & svg { 60 | width: 1rem; 61 | height: 1rem; 62 | } 63 | 64 | &:hover { 65 | & svg { 66 | opacity: 0.7; 67 | } 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /styleguide.config.js: -------------------------------------------------------------------------------- 1 | const {VueLoaderPlugin} = require('vue-loader') 2 | const path = require('path') 3 | const glob = require('glob') 4 | 5 | const sections = (() => { 6 | const docs = glob 7 | .sync('docs/*.md') 8 | .map(p => ({name: path.basename(p, '.md'), content: p})) 9 | const demos = [] 10 | let faq = '' // 约定至多只有一个faq.md 11 | const guides = [] 12 | docs.forEach(d => { 13 | if (/^faq$/i.test(d.name)) { 14 | d.name = d.name.toUpperCase() 15 | faq = d 16 | } else if (/^guide-/.test(d.name)) { 17 | guides.push(d) 18 | } else { 19 | demos.push(d) 20 | } 21 | }) 22 | return [ 23 | { 24 | name: 'Components', 25 | components: 'src/*.vue', 26 | usageMode: 'expand' 27 | }, 28 | { 29 | name: 'Demo', 30 | sections: demos, 31 | sectionDepth: 2 32 | }, 33 | ...(faq ? [faq] : []), 34 | ...(guides.length ? [{name: 'Guide', sections: guides}] : []) 35 | ] 36 | })() 37 | 38 | module.exports = { 39 | styleguideDir: 'docs', 40 | pagePerSection: true, 41 | ribbon: { 42 | url: 'https://github.com/FEMessage/el-data-tree' 43 | }, 44 | sections, 45 | require: ['./styleguide/global.requires.js'], 46 | webpackConfig: { 47 | module: { 48 | rules: [ 49 | { 50 | test: /\.vue$/, 51 | loader: 'vue-loader' 52 | }, 53 | { 54 | test: /\.js?$/, 55 | exclude: /node_modules/, 56 | loader: 'babel-loader' 57 | }, 58 | { 59 | test: /\.css$/, 60 | loaders: ['style-loader', 'css-loader'] 61 | }, 62 | { 63 | test: /\.less$/, 64 | loaders: ['vue-style-loader', 'css-loader', 'less-loader'] 65 | }, 66 | { 67 | test: /\.(woff2?|eot|[ot]tf)(\?.*)?$/, 68 | loader: 'file-loader' 69 | } 70 | ] 71 | }, 72 | plugins: [new VueLoaderPlugin()] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /styleguide/global.requires.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | import ElementUI from 'element-ui' 4 | import 'element-ui/lib/theme-chalk/index.css' 5 | import ElFormRenderer from '@femessage/el-form-renderer' 6 | 7 | const axiosInstance = axios.create() 8 | axiosInstance.interceptors.request.use(config => { 9 | config.url += `?requestid=${Math.random()}` 10 | return config 11 | }) 12 | Vue.prototype.$axios = axiosInstance 13 | Vue.use(ElementUI) 14 | Vue.component('el-form-renderer', ElFormRenderer) 15 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | import sum from './sum' 2 | 3 | test('main', () => { 4 | expect(sum(1, 2)).toBe(3) 5 | }) 6 | -------------------------------------------------------------------------------- /test/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(a, b) { 2 | return a + b 3 | } 4 | --------------------------------------------------------------------------------