├── .browserslistrc
├── .eslintrc.cjs
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ ├── build-test.yml
│ ├── vitepress-deploy.yml
│ └── vuepress-deploy.yml
├── .gitignore
├── LICENSE
├── README.md
├── dist
├── index.css
├── vue-grid-layout-v3.cjs
├── vue-grid-layout-v3.iife.js
├── vue-grid-layout-v3.js
└── vue-grid-layout-v3.umd.js
├── favicon.ico
├── index.html
├── jest.config.js
├── package-lock.json
├── package.json
├── src
├── app.vue
├── assets
│ └── logo.png
├── components
│ ├── grid-item.vue
│ ├── grid-layout.vue
│ └── index.js
├── custom-drag-element.vue
├── helpers
│ ├── dom.js
│ ├── draggable-utils.js
│ ├── responsive-utils.js
│ └── utils.js
├── main.js
└── test-element.vue
├── test
├── interact-test.html
├── interact-test.js
└── unit
│ ├── GridItem.spec.js
│ └── utils.spec.js
├── vite.config.js
└── website
├── .editorconfig
├── .eslintrc.cjs
├── .gitignore
├── .vitepress
├── config.mjs
└── theme
│ ├── custom.css
│ ├── index.js
│ └── style.css
├── favicon.ico
├── index.html
├── package-lock.json
├── package.json
├── src
├── app.vue
├── example
│ ├── 01-basic.vue
│ ├── 02-events.vue
│ ├── 03-multiple-grids.vue
│ ├── 04-allow-ignore.vue
│ ├── 05-mirrored.vue
│ ├── 06-responsive.vue
│ ├── 07-prevent-collision.vue
│ ├── 08-responsive-predefined-layouts.vue
│ ├── 09-dynamic-add-remove.vue
│ ├── 10-drag-from-outside.vue
│ ├── 11-bounded.vue
│ ├── dom.js
│ ├── styling-grid-lines.vue
│ ├── styling-placeholder.vue
│ ├── test-element.vue
│ └── usage.vue
├── guide
│ ├── 01-basic.md
│ ├── 02-events.md
│ ├── 03-multiple-grids.md
│ ├── 04-allow-ignore.md
│ ├── 05-mirrored.md
│ ├── 06-responsive.md
│ ├── 07-prevent-collision.md
│ ├── 08-responsive-predefined-layouts.md
│ ├── 09-dynamic-add-remove.md
│ ├── 10-drag-from-outside.md
│ ├── 11-bounded.md
│ ├── auto-size.md
│ ├── events.md
│ ├── index.md
│ ├── properties.md
│ ├── readme.md
│ ├── styling.md
│ └── usage.md
├── index.md
├── main.js
├── public
│ ├── favicon.ico
│ └── logo.png
├── readme.md
└── zh
│ ├── README.md
│ └── guide
│ ├── 01-basic.md
│ ├── 02-events.md
│ ├── 03-multiple-grids.md
│ ├── 04-allow-ignore.md
│ ├── 05-mirrored.md
│ ├── 06-responsive.md
│ ├── 07-prevent-collision.md
│ ├── 08-responsive-predefined-layouts.md
│ ├── 09-dynamic-add-remove.md
│ ├── 10-drag-from-outside.md
│ ├── 11-bounded.md
│ ├── README.md
│ ├── auto-size.md
│ ├── events.md
│ ├── examples.md
│ ├── properties.md
│ ├── styling.md
│ └── usage.md
└── vite.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
4 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | const config = {
3 | root: true,
4 | extends: [
5 | 'plugin:vue/vue3-essential',
6 | 'eslint:recommended',
7 | 'airbnb-base',
8 | ],
9 | // env: {
10 | // // 'vue/setup-compiler-macros': true,
11 | // es6: true,
12 | // },
13 | // parserOptions: {
14 | // },
15 | parser: 'vue-eslint-parser',
16 | parserOptions: {
17 | ecmaVersion: 'latest',
18 | // parser: '@babel/eslint-parser',
19 | ecmaFeatures: {
20 | jsx: true,
21 | },
22 | },
23 | rules: {
24 | // 修改的规则
25 | 'no-multi-spaces': [2, { ignoreEOLComments: true }],
26 |
27 | // 关闭vue的规则
28 | 'vue/multi-word-component-names': 0,
29 | 'vue/require-component-is': 0,
30 | 'vue/no-v-for-template-key-on-child': 0,
31 | 'vue/no-v-text-v-html-on-component': 0,
32 |
33 | // 关闭import规则
34 | 'import/extensions': 0,
35 | 'import/no-extraneous-dependencies': 0,
36 | 'import/no-dynamic-require': 0,
37 | 'import/no-unresolved': 0,
38 | 'import/prefer-default-export': 0,
39 |
40 | // 关闭airbnb规则
41 | 'arrow-parens': 0,
42 | 'arrow-body-style': 0,
43 | 'consistent-return': 0,
44 | 'default-param-last': 0,
45 | 'default-case': 0,
46 | 'global-require': 0,
47 | 'object-curly-newline': 0,
48 | 'prefer-destructuring': 0,
49 | radix: 0,
50 | 'max-len': 0,
51 | 'newline-per-chained-call': 0,
52 | 'no-bitwise': 0,
53 | 'no-console': 0,
54 | 'no-control-regex': 0,
55 | 'no-cond-assign': 0,
56 | 'no-continue': 0,
57 | 'no-lonely-if': 0,
58 | 'no-return-assign': 0,
59 | 'no-restricted-syntax': 0,
60 | 'no-param-reassign': 0,
61 | 'no-plusplus': 0,
62 | 'no-use-before-define': 0,
63 | 'no-multiple-empty-lines': 0,
64 | 'no-shadow': 0,
65 |
66 | // 关闭其他规则
67 | 'prettier/prettier': 0,
68 | camelcase: 0,
69 |
70 | // 增加的规则
71 | 'no-debugger': 2,
72 | },
73 | ignorePatterns: [
74 | 'coverage/**',
75 | 'public/**',
76 | 'dist/**',
77 | 'website/**',
78 | 'test/**/*',
79 | ],
80 | };
81 |
82 | // 开发测试阶段降低规则要求
83 | if (process.env.NODE_ENV !== 'production') {
84 | Object.assign(config.rules, {
85 | 'vue/no-unused-vars': 1,
86 | 'vue/valid-template-root': 1,
87 | 'vue/return-in-computed-property': 1,
88 | 'vue/valid-v-for': 1,
89 |
90 | 'import/newline-after-import': 1,
91 |
92 | 'array-bracket-spacing': 1,
93 | 'brace-style': 1,
94 | 'block-spacing': 1,
95 | 'comma-dangle': 1,
96 | 'comma-spacing': 1,
97 | indent: [1, 2, { SwitchCase: 1 }],
98 | 'key-spacing': 1,
99 | 'keyword-spacing': 1,
100 | 'operator-linebreak': 1,
101 | 'prefer-const': 1,
102 | 'padded-blocks': 1,
103 | 'quote-props': 1,
104 | semi: 1,
105 | 'spaced-comment': 1,
106 | 'space-before-blocks': 1,
107 | 'space-before-function-paren': 1,
108 | 'space-infix-ops': 1,
109 | 'space-in-parens': 1,
110 | 'no-debugger': 1,
111 | 'no-empty': 1,
112 | 'no-empty-function': 1,
113 | 'no-unused-vars': 1,
114 | 'no-multi-spaces': [1, { ignoreEOLComments: true }],
115 | 'no-unreachable': 1,
116 | });
117 | }
118 |
119 | module.exports = config;
120 |
121 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: merfais
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Software version (please complete the following information):**
11 | - Browser [e.g. chrome, safari]
12 | - Vue Version [e.g. 2.5.7]
13 | - vue-grid-layout Version: [e.g. 2.3.3]
14 |
15 | **Describe the bug**
16 | A clear and concise description of what the bug is.
17 |
18 | Please use the [CodeSandbox Template](https://codesandbox.io/s/5wy3rz5z1x?module=%2Fsrc%2FShowcaseLayout.js) to demonstrate your bug. It is much easier for us to help you if you do.
19 |
20 |
21 | **To Reproduce**
22 | Steps to reproduce the behavior:
23 | 1. Go to '...'
24 | 2. Click on '....'
25 | 3. Scroll down to '....'
26 | 4. See error
27 |
28 | **Expected behavior**
29 | A clear and concise description of what you expected to happen.
30 |
31 | **Screenshots**
32 | If applicable, add screenshots to help explain your problem.
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## If you have a feature request, please try to implement it before requesting it.
This is free software and the author is busy with other projects.
11 |
12 | **Is your feature request related to a problem? Please describe.**
13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
14 |
15 | **Describe the solution you'd like**
16 | A clear and concise description of what you want to happen.
17 |
18 | **Describe alternatives you've considered**
19 | A clear and concise description of any alternative solutions or features you've considered.
20 |
21 | **Additional context**
22 | Add any other context or screenshots about the feature request here.
23 |
--------------------------------------------------------------------------------
/.github/workflows/build-test.yml:
--------------------------------------------------------------------------------
1 | name: Build and Test
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | matrix:
16 | node-version: [18.x, 20.x, 22.x]
17 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
18 |
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Use Node.js ${{ matrix.node-version }}
22 | uses: actions/setup-node@v1
23 | with:
24 | node-version: ${{ matrix.node-version }}
25 | - name: Install dependency
26 | run: npm i
27 | - name: Lint check
28 | run: npm run lint
29 | - name: Build
30 | run: npm run build
31 | # - name: Unit test
32 | # run: yarn test:unit
33 |
--------------------------------------------------------------------------------
/.github/workflows/vitepress-deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy VitePress site to Pages
2 | on:
3 | push:
4 | branches:
5 | - master
6 | # 允许你从 Actions 选项卡手动运行此工作流程
7 | workflow_dispatch:
8 |
9 | # 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages
10 | permissions:
11 | contents: read
12 | pages: write
13 | id-token: write
14 |
15 | # 只允许同时进行一次部署,跳过正在运行和最新队列之间的运行队列
16 | # 但是,不要取消正在进行的运行,因为我们希望允许这些生产部署完成
17 | concurrency:
18 | group: pages
19 | cancel-in-progress: false
20 |
21 | jobs:
22 | # 构建工作
23 | build:
24 | runs-on: ubuntu-latest
25 | steps:
26 | - name: Checkout
27 | uses: actions/checkout@v4
28 | with:
29 | fetch-depth: 0 # 如果未启用 lastUpdated,则不需要
30 | # - uses: pnpm/action-setup@v3 # 如果使用 pnpm,请取消此区域注释
31 | # with:
32 | # version: 9
33 | # - uses: oven-sh/setup-bun@v1 # 如果使用 Bun,请取消注释
34 | - name: Setup Node
35 | uses: actions/setup-node@v4
36 | with:
37 | node-version: 20
38 | cache: npm # 或 pnpm / yarn
39 | - name: Setup Pages
40 | uses: actions/configure-pages@v4
41 | - name: Install dependencies
42 | run: cd website && npm install # 或 pnpm install / yarn install / bun install
43 | - name: Build with VitePress
44 | run: cd website && npm run docs:build # 或 pnpm docs:build / yarn docs:build / bun run docs:build
45 | - name: Upload artifact
46 | uses: actions/upload-pages-artifact@v3
47 | with:
48 | path: website/.vitepress/dist
49 |
50 | # 部署工作
51 | deploy:
52 | environment:
53 | name: github-pages
54 | url: ${{ steps.deployment.outputs.page_url }}
55 | needs: build
56 | runs-on: ubuntu-latest
57 | name: Deploy
58 | steps:
59 | - name: Deploy to GitHub Pages
60 | id: deployment
61 | uses: actions/deploy-pages@v4
62 |
63 |
--------------------------------------------------------------------------------
/.github/workflows/vuepress-deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy vuepress website
2 | on:
3 | # push:
4 | # branches:
5 | # - master
6 | # 允许你从 Actions 选项卡手动运行此工作流程
7 | workflow_dispatch:
8 | jobs:
9 | build-and-deploy:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@master
14 |
15 | - uses: actions/setup-node@v2
16 | with:
17 | node-version: '16'
18 |
19 | - name: vuepress-deploy
20 | uses: jenkey2011/vuepress-deploy@master
21 | env:
22 | TARGET_REPO: merfais/vue-grid-layout-v3
23 | TARGET_BRANCH: gh-pages
24 | BUILD_SCRIPT: cd website && yarn && yarn build
25 | BUILD_DIR: public
26 | with:
27 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | #/dist
4 | dist/demo.html
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw*
23 |
24 | yarn-error.log
25 | cache/**
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 greyby
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 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | vue-grid-layout-v3
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
24 |
25 | ## What is Vue Grid Layout?
26 |
27 | vue-grid-layout is a grid layout system, like [Gridster](http://dsmorse.github.io/gridster.js/), for Vue.js. **Heavily inspired by [React-Grid-Layout](https://github.com/STRML/react-grid-layout)**
28 |
29 | ## Features
30 |
31 | * Draggable widgets
32 | * Resizable widgets
33 | * Static widgets
34 | * Bounds checking for dragging and resizing
35 | * Widgets may be added or removed without rebuilding grid
36 | * Layout can be serialized and restored
37 | * Automatic RTL support (resizing not working with RTL on 2.2.0)
38 | * Responsive
39 |
40 | ## **Current version:** 3.1.0 (Supports Vue 3.2+)
41 |
42 | #### **upgrading from version 3.0 to version 3.1 has some break change**
43 | + GridLayout expose changed: `{ placeholderRef, emitter }` -> `{ el, placeholderEl, emitter, placeholder }`
44 | + GridItem expose changed: `{ calcXY, domRef }` -> `{ calcXY, el }`
45 |
46 | #### **For legacy browsers**, like IE11, use version [2.3.12-legacy](https://github.com/jbaysolutions/vue-grid-layout/tree/legacy)
47 | #### **For Vue 2.1.10+ use version [2.4.0](https://github.com/jbaysolutions/vue-grid-layout/tree/2.4.0)**
48 | #### **For Vue 2.1.10 and below use version [2.1.3](https://github.com/jbaysolutions/vue-grid-layout/tree/2.1.3)**
49 | #### **For Vue 1 use version [1.0.3](https://github.com/jbaysolutions/vue-grid-layout/tree/1.0.3)**
50 |
51 | ## Documentation
52 |
53 | Check out the Documentation Website
54 |
55 |
58 |
59 | ## Contribute
60 |
61 | If you have a feature request, please add it as an issue or make a pull request.
62 |
63 |
64 | 3.0 version Developed by CoffeeBi
65 |
66 | Developed by JBay Solutions
67 |
--------------------------------------------------------------------------------
/dist/index.css:
--------------------------------------------------------------------------------
1 | .vue-grid-item[data-v-99aff433]{transition:all .2s ease;transition-property:left,top,right}.vue-grid-item.no-touch[data-v-99aff433]{touch-action:none}.vue-grid-item.cssTransforms[data-v-99aff433]{transition-property:transform;left:0;right:auto}.vue-grid-item.cssTransforms.render-rtl[data-v-99aff433]{left:auto;right:0}.vue-grid-item.resizing[data-v-99aff433]{opacity:.6;z-index:3}.vue-grid-item.vue-draggable-dragging[data-v-99aff433]{transition:none;z-index:3}.vue-grid-item.vue-grid-placeholder[data-v-99aff433]{background:red;opacity:.2;transition-duration:.1s;z-index:2;-webkit-user-select:none;user-select:none}.vue-grid-item>.vue-resizable-handle[data-v-99aff433]{position:absolute;width:20px;height:20px;bottom:0;right:0;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=);background-position:bottom right;padding:0 3px 3px 0;background-repeat:no-repeat;background-origin:content-box;box-sizing:border-box;cursor:se-resize}.vue-grid-item>.vue-rtl-resizable-handle[data-v-99aff433]{bottom:0;left:0;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAuMDAwMDAwMDAwMDAwMDAyIiBoZWlnaHQ9IjEwLjAwMDAwMDAwMDAwMDAwMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDwhLS0gQ3JlYXRlZCB3aXRoIE1ldGhvZCBEcmF3IC0gaHR0cDovL2dpdGh1Yi5jb20vZHVvcGl4ZWwvTWV0aG9kLURyYXcvIC0tPgogPGc+CiAgPHRpdGxlPmJhY2tncm91bmQ8L3RpdGxlPgogIDxyZWN0IGZpbGw9Im5vbmUiIGlkPSJjYW52YXNfYmFja2dyb3VuZCIgaGVpZ2h0PSIxMiIgd2lkdGg9IjEyIiB5PSItMSIgeD0iLTEiLz4KICA8ZyBkaXNwbGF5PSJub25lIiBvdmVyZmxvdz0idmlzaWJsZSIgeT0iMCIgeD0iMCIgaGVpZ2h0PSIxMDAlIiB3aWR0aD0iMTAwJSIgaWQ9ImNhbnZhc0dyaWQiPgogICA8cmVjdCBmaWxsPSJ1cmwoI2dyaWRwYXR0ZXJuKSIgc3Ryb2tlLXdpZHRoPSIwIiB5PSIwIiB4PSIwIiBoZWlnaHQ9IjEwMCUiIHdpZHRoPSIxMDAlIi8+CiAgPC9nPgogPC9nPgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxsaW5lIGNhbnZhcz0iI2ZmZmZmZiIgY2FudmFzLW9wYWNpdHk9IjEiIHN0cm9rZS1saW5lY2FwPSJ1bmRlZmluZWQiIHN0cm9rZS1saW5lam9pbj0idW5kZWZpbmVkIiBpZD0ic3ZnXzEiIHkyPSItNzAuMTc4NDA3IiB4Mj0iMTI0LjQ2NDE3NSIgeTE9Ii0zOC4zOTI3MzciIHgxPSIxNDQuODIxMjg5IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlPSIjMDAwIiBmaWxsPSJub25lIi8+CiAgPGxpbmUgc3Ryb2tlPSIjNjY2NjY2IiBzdHJva2UtbGluZWNhcD0idW5kZWZpbmVkIiBzdHJva2UtbGluZWpvaW49InVuZGVmaW5lZCIgaWQ9InN2Z181IiB5Mj0iOS4xMDY5NTciIHgyPSIwLjk0NzI0NyIgeTE9Ii0wLjAxODEyOCIgeDE9IjAuOTQ3MjQ3IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiLz4KICA8bGluZSBzdHJva2UtbGluZWNhcD0idW5kZWZpbmVkIiBzdHJva2UtbGluZWpvaW49InVuZGVmaW5lZCIgaWQ9InN2Z183IiB5Mj0iOSIgeDI9IjEwLjA3MzUyOSIgeTE9IjkiIHgxPSItMC42NTU2NCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM2NjY2NjYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+);background-position:bottom left;padding-left:3px;background-repeat:no-repeat;background-origin:content-box;cursor:sw-resize;right:auto}.vue-grid-item.disable-userselect[data-v-99aff433]{-webkit-user-select:none;user-select:none}.vue-grid-layout[data-v-a10aee95]{position:relative;transition:height .2s ease}
2 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merfais/vue-grid-layout-v3/a669942fa85c80211767b89acddbe6211319ffe2/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vue Grid Layout
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleFileExtensions: [
3 | 'js',
4 | 'json',
5 | 'vue',
6 | ],
7 | moduleNameMapper: {
8 | '^@/(.*)$': '/src/$1',
9 | },
10 | transformIgnorePatterns: [
11 | '/node_modules/(?!@babel|@interactjs)',
12 | ],
13 | transform: {
14 | '^.+\\.js$': '/node_modules/babel-jest',
15 | '.*\\.(vue)$': '/node_modules/vue-jest',
16 | },
17 | coverageDirectory: '/test/unit/coverage',
18 | collectCoverageFrom: [
19 | 'src/**/*.{js,vue}',
20 | '!src/main.js',
21 | '!src/router/index.js',
22 | '!**/node_modules/**',
23 | ],
24 | };
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-grid-layout-v3",
3 | "version": "3.1.2",
4 | "description": "A draggable and resizable grid layout, as a Vue component.",
5 | "keywords": [
6 | "grid",
7 | "vuejs",
8 | "drag",
9 | "draggable",
10 | "resize",
11 | "resizable",
12 | "fluid",
13 | "responsive"
14 | ],
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/merfais/vue-grid-layout-v3.git"
18 | },
19 | "author": "coffeebi ",
20 | "homepage": "https://github.com/merfais/vue-grid-layout-v3",
21 | "type": "module",
22 | "main": "./dist/vue-grid-layout-v3.umd.js",
23 | "module": "./dist/vue-grid-layout-v3.js",
24 | "unpkg": "./dist/vue-grid-layout-v3.umd.js",
25 | "exports": {
26 | "import": "./dist/vue-grid-layout-v3.js",
27 | "require": "./dist/vue-grid-layout-v3.cjs"
28 | },
29 | "scripts": {
30 | "dev": "vite",
31 | "build": "vite build",
32 | "preview": "vite preview",
33 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs",
34 | "lint:fix": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix"
35 | },
36 | "dependencies": {
37 | "@interactjs/actions": "^1.10.27",
38 | "@interactjs/auto-scroll": "^1.10.27",
39 | "@interactjs/auto-start": "^1.10.27",
40 | "@interactjs/dev-tools": "^1.10.27",
41 | "@interactjs/interact": "^1.10.27",
42 | "@interactjs/modifiers": "^1.10.27",
43 | "element-resize-detector": "^1.2.4",
44 | "mitt": "^3.0.1"
45 | },
46 | "devDependencies": {
47 | "@rollup/plugin-eslint": "^9.0.5",
48 | "@vitejs/plugin-vue": "^5.0.5",
49 | "@vitejs/plugin-vue-jsx": "^4.0.0",
50 | "autoprefixer": "^10.4.20",
51 | "eslint": "^8.57.0",
52 | "eslint-config-airbnb-base": "^15.0.0",
53 | "eslint-plugin-vue": "^9.23.0",
54 | "vite": "^5.3.1",
55 | "vite-plugin-lib-inject-css": "^2.1.1",
56 | "vue": "^3.4.29",
57 | "vue-eslint-parser": "^9.4.3"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/app.vue:
--------------------------------------------------------------------------------
1 |
182 |
183 |
184 |
Vue Grid Layout
185 |
186 |
187 |
188 |
189 | {{item.i}}:{{item}}
190 |
191 |
192 |
193 |
194 |
218 |
241 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
309 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merfais/vue-grid-layout-v3/a669942fa85c80211767b89acddbe6211319ffe2/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/grid-layout.vue:
--------------------------------------------------------------------------------
1 |
523 |
524 |
525 |
526 |
535 |
536 |
537 |
543 |
544 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import GridItem from './grid-item.vue';
2 | import GridLayout from './grid-layout.vue';
3 |
4 | export default function install(app) {
5 | if (install.installed) return;
6 | install.installed = true;
7 | app.component('GridLayout', GridLayout);
8 | app.component('GridItem', GridItem);
9 | }
10 |
11 | export { GridLayout, GridItem, install };
12 |
13 |
--------------------------------------------------------------------------------
/src/custom-drag-element.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{text}}
4 |
5 |
6 |
7 |
8 |
26 |
42 |
--------------------------------------------------------------------------------
/src/helpers/dom.js:
--------------------------------------------------------------------------------
1 | // let currentDir: "ltr" | "rtl" | "auto" = "auto";
2 | let currentDir = 'auto';
3 |
4 | function hasDocument() {
5 | return (typeof document !== 'undefined');
6 | }
7 |
8 | function hasWindow() {
9 | return (typeof window !== 'undefined');
10 | }
11 |
12 | export function getDocumentDir() {
13 | if (!hasDocument()) {
14 | return currentDir;
15 | }
16 | const direction = (typeof document.dir !== 'undefined')
17 | ? document.dir
18 | : document.getElementsByTagName('html')[0].getAttribute('dir');
19 | return direction;
20 | }
21 |
22 | // export function setDocumentDir(dir: "ltr" | "rtl" | "auto"){
23 | export function setDocumentDir(dir) {
24 | if (!hasDocument) {
25 | currentDir = dir;
26 | return;
27 | }
28 |
29 | const html = document.getElementsByTagName('html')[0];
30 | html.setAttribute('dir', dir);
31 | }
32 |
33 | const cb = () => {};
34 | // export function addWindowEventListener(event:string, callback: () => mixed){
35 | export function addWindowEventListener(event, callback = cb) {
36 | if (!hasWindow) {
37 | callback();
38 | return;
39 | }
40 | window.addEventListener(event, callback);
41 | }
42 |
43 | export function removeWindowEventListener(event, callback = cb) {
44 | if (!hasWindow) {
45 | return;
46 | }
47 | window.removeEventListener(event, callback);
48 | }
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/helpers/draggable-utils.js:
--------------------------------------------------------------------------------
1 | // Get {x, y} positions from event.
2 | export function getControlPosition(e) {
3 | return offsetXYFromParentOf(e);
4 | }
5 |
6 |
7 | // Get from offsetParent
8 | export function offsetXYFromParentOf(evt) {
9 | const offsetParent = evt.target.offsetParent || document.body;
10 | const offsetParentRect = evt.offsetParent === document.body ? { left: 0, top: 0 } : offsetParent.getBoundingClientRect();
11 |
12 | const x = evt.clientX + offsetParent.scrollLeft - offsetParentRect.left;
13 | const y = evt.clientY + offsetParent.scrollTop - offsetParentRect.top;
14 |
15 | /* const x = Math.round(evt.clientX + offsetParent.scrollLeft - offsetParentRect.left);
16 | const y = Math.round(evt.clientY + offsetParent.scrollTop - offsetParentRect.top); */
17 |
18 |
19 | return { x, y };
20 | }
21 |
22 |
23 | // Create an data object exposed by 's events
24 | export function createCoreData(lastX, lastY, x, y) {
25 | // State changes are often (but not always!) async. We want the latest value.
26 | const isStart = !isNum(lastX);
27 |
28 | if (isStart) {
29 | // If this is our first move, use the x and y as last coords.
30 | return {
31 | deltaX: 0,
32 | deltaY: 0,
33 | lastX: x,
34 | lastY: y,
35 | x,
36 | y,
37 | };
38 | }
39 | // Otherwise calculate proper values.
40 | return {
41 | deltaX: x - lastX,
42 | deltaY: y - lastY,
43 | lastX,
44 | lastY,
45 | x,
46 | y,
47 | };
48 | }
49 |
50 |
51 | function isNum(num) {
52 | return typeof num === 'number' && !Number.isNaN(num);
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/src/helpers/responsive-utils.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import { cloneLayout, compact, correctBounds } from './utils';
4 |
5 | // import type {Layout} from './utils';
6 | // export type ResponsiveLayout = {lg?: Layout, md?: Layout, sm?: Layout, xs?: Layout, xxs?: Layout};
7 | // type Breakpoint = string;
8 | // type Breakpoints = {lg?: number, md?: number, sm?: number, xs?: number, xxs?: number};
9 |
10 | /**
11 | * Given a width, find the highest breakpoint that matches is valid for it (width > breakpoint).
12 | *
13 | * @param {Object} breakpoints Breakpoints object (e.g. {lg: 1200, md: 960, ...})
14 | * @param {Number} width Screen width.
15 | * @return {String} Highest breakpoint that is less than width.
16 | */
17 | // export function getBreakpointFromWidth(breakpoints: Breakpoints, width: number): Breakpoint {
18 | export function getBreakpointFromWidth(breakpoints, width) {
19 | const sorted = sortBreakpoints(breakpoints);
20 | let matching = sorted[0];
21 | for (let i = 1, len = sorted.length; i < len; i++) {
22 | const breakpointName = sorted[i];
23 | if (width > breakpoints[breakpointName]) matching = breakpointName;
24 | }
25 | return matching;
26 | }
27 |
28 |
29 | /**
30 | * Given a breakpoint, get the # of cols set for it.
31 | * @param {String} breakpoint Breakpoint name.
32 | * @param {Object} cols Map of breakpoints to cols.
33 | * @return {Number} Number of cols.
34 | */
35 | // export function getColsFromBreakpoint(breakpoint: Breakpoint, cols: Breakpoints): number {
36 | export function getColsFromBreakpoint(breakpoint, cols) {
37 | if (!cols[breakpoint]) {
38 | throw new Error(`ResponsiveGridLayout: \`cols\` entry for breakpoint ${breakpoint} is missing!`);
39 | }
40 | return cols[breakpoint];
41 | }
42 |
43 | /**
44 | * Given existing layouts and a new breakpoint, find or generate a new layout.
45 | *
46 | * This finds the layout above the new one and generates from it, if it exists.
47 | *
48 | * @param {Array} orgLayout Original layout.
49 | * @param {Object} layouts Existing layouts.
50 | * @param {Array} breakpoints All breakpoints.
51 | * @param {String} breakpoint New breakpoint.
52 | * @param {String} breakpoint Last breakpoint (for fallback).
53 | * @param {Number} cols Column count at new breakpoint.
54 | * @param {Boolean} verticalCompact Whether or not to compact the layout
55 | * vertically.
56 | * @return {Array} New layout.
57 | */
58 | // export function findOrGenerateResponsiveLayout(orgLayout: Layout, layouts: ResponsiveLayout, breakpoints: Breakpoints,
59 | // breakpoint: Breakpoint, lastBreakpoint: Breakpoint,
60 | // cols: number, verticalCompact: boolean): Layout {
61 | export function findOrGenerateResponsiveLayout(
62 | orgLayout,
63 | layouts,
64 | breakpoints,
65 | breakpoint,
66 | cols,
67 | verticalCompact,
68 | ) {
69 | // If it already exists, just return it.
70 | if (layouts[breakpoint]) return cloneLayout(layouts[breakpoint]);
71 | // Find or generate the next layout
72 | let layout = orgLayout;
73 |
74 | const breakpointsSorted = sortBreakpoints(breakpoints);
75 | const breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint));
76 | for (let i = 0, len = breakpointsAbove.length; i < len; i++) {
77 | const b = breakpointsAbove[i];
78 | if (layouts[b]) {
79 | layout = layouts[b];
80 | break;
81 | }
82 | }
83 | layout = cloneLayout(layout || []); // clone layout so we don't modify existing items
84 | return compact(correctBounds(layout, { cols }), verticalCompact);
85 | }
86 |
87 | // // export function generateResponsiveLayout(layout: Layout, breakpoints: Breakpoints,
88 | // // breakpoint: Breakpoint, lastBreakpoint: Breakpoint,
89 | // // cols: number, verticalCompact: boolean): Layout {
90 | // export function generateResponsiveLayout(
91 | // layout,
92 | // breakpoints,
93 | // breakpoint,
94 | // lastBreakpoint,
95 | // cols,
96 | // verticalCompact,
97 | // ) {
98 | // // If it already exists, just return it.
99 | // /* if (layouts[breakpoint]) return cloneLayout(layouts[breakpoint]);
100 | // // Find or generate the next layout
101 | // let layout = layouts[lastBreakpoint]; */
102 | // /* const breakpointsSorted = sortBreakpoints(breakpoints);
103 | // const breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint));
104 | // for (let i = 0, len = breakpointsAbove.length; i < len; i++) {
105 | // const b = breakpointsAbove[i];
106 | // if (layouts[b]) {
107 | // layout = layouts[b];
108 | // break;
109 | // }
110 | // } */
111 | // layout = cloneLayout(layout || []); // clone layout so we don't modify existing items
112 | // return compact(correctBounds(layout, { cols }), verticalCompact);
113 | // }
114 |
115 | /**
116 | * Given breakpoints, return an array of breakpoints sorted by width. This is usually
117 | * e.g. ['xxs', 'xs', 'sm', ...]
118 | *
119 | * @param {Object} breakpoints Key/value pair of breakpoint names to widths.
120 | * @return {Array} Sorted breakpoints.
121 | */
122 | // export function sortBreakpoints(breakpoints: Breakpoints): Array {
123 | export function sortBreakpoints(breakpoints) {
124 | // const keys: Array = Object.keys(breakpoints);
125 | const keys = Object.keys(breakpoints);
126 | return keys.sort((a, b) => {
127 | return breakpoints[a] - breakpoints[b];
128 | });
129 | }
130 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import App from './app.vue';
3 |
4 | createApp(App).mount('#app');
5 |
6 |
--------------------------------------------------------------------------------
/src/test-element.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 | {{text}}
24 |
25 | x
26 |
27 |
28 |
36 |
37 |
--------------------------------------------------------------------------------
/test/interact-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Interact TEST
6 |
7 |
30 |
31 |
32 |
33 |
34 | Resize from any edge or corner
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/test/interact-test.js:
--------------------------------------------------------------------------------
1 | function dragMoveListener (event) {
2 | var target = event.target,
3 | // keep the dragged position in the data-x/data-y attributes
4 | x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
5 | y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
6 |
7 | // translate the element
8 | target.style.webkitTransform =
9 | target.style.transform =
10 | 'translate(' + x + 'px, ' + y + 'px)';
11 |
12 | // update the posiion attributes
13 | target.setAttribute('data-x', x);
14 | target.setAttribute('data-y', y);
15 | }
16 |
17 | // this is used later in the resizing and gesture demos
18 | window.dragMoveListener = dragMoveListener;
19 |
20 |
21 | interact('.resize-drag')
22 | .draggable({
23 | onmove: window.dragMoveListener,
24 | restrict: {
25 | restriction: 'parent',
26 | elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
27 | },
28 | })
29 | .resizable({
30 | // resize from all edges and corners
31 | edges: { left: true, right: true, bottom: true, top: true },
32 |
33 | // keep the edges inside the parent
34 | restrictEdges: {
35 | outer: 'parent',
36 | endOnly: true,
37 | },
38 |
39 | // minimum size
40 | restrictSize: {
41 | min: { width: 100, height: 50 },
42 | },
43 |
44 | inertia: true,
45 | })
46 | .on('resizemove', function (event) {
47 | var target = event.target,
48 | x = (parseFloat(target.getAttribute('data-x')) || 0),
49 | y = (parseFloat(target.getAttribute('data-y')) || 0);
50 |
51 | // update the element's style
52 | target.style.width = event.rect.width + 'px';
53 | target.style.height = event.rect.height + 'px';
54 |
55 | // translate when resizing from top or left edges
56 | x += event.deltaRect.left;
57 | y += event.deltaRect.top;
58 |
59 | target.style.webkitTransform = target.style.transform =
60 | 'translate(' + x + 'px,' + y + 'px)';
61 |
62 | target.setAttribute('data-x', x);
63 | target.setAttribute('data-y', y);
64 | target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height);
65 | });
--------------------------------------------------------------------------------
/test/unit/GridItem.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import GridLayout from '../../src/components/GridLayout.vue'
3 |
4 | let layout
5 |
6 | describe('GridLayout test', () => {
7 | beforeAll(()=>{
8 | let testLayout = [{"x":0,"y":0,"w":2,"h":2,"i":"0", resizable: true, draggable: true, static: false, minY: 0, maxY: 2}];
9 | layout = JSON.parse(JSON.stringify(testLayout))
10 | })
11 |
12 | describe('Interface test', () => {
13 | it('should render correct contents', () => {
14 | const wrapper = shallowMount(GridLayout, {
15 | propsData: {
16 | layout: layout
17 | }
18 | })
19 | const grid = wrapper.findAll('.vue-grid-layout');
20 | expect(grid.selector).toEqual('.vue-grid-layout');
21 | })
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/test/unit/utils.spec.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-env jest */
3 |
4 | import {
5 | bottom,
6 | collides,
7 | compact,
8 | moveElement,
9 | sortLayoutItemsByRowCol,
10 | validateLayout
11 | } from "../../src/helpers/utils";
12 |
13 | describe("bottom", () => {
14 | it("Handles an empty layout as input", () => {
15 | expect(bottom([])).toEqual(0);
16 | });
17 |
18 | it("Returns the bottom coordinate of the layout", () => {
19 | expect(
20 | bottom([
21 | { i: "1", x: 0, y: 1, w: 1, h: 1 },
22 | { i: "2", x: 1, y: 2, w: 1, h: 1 }
23 | ])
24 | ).toEqual(3);
25 | });
26 | });
27 |
28 | describe("sortLayoutItemsByRowCol", () => {
29 | it("should sort by top to bottom right", () => {
30 | const layout = [
31 | { x: 1, y: 1, w: 1, h: 1, i: "2" },
32 | { x: 1, y: 0, w: 1, h: 1, i: "1" },
33 | { x: 0, y: 1, w: 2, h: 2, i: "3" }
34 | ];
35 | expect(sortLayoutItemsByRowCol(layout)).toEqual([
36 | { x: 1, y: 0, w: 1, h: 1, i: "1" },
37 | { x: 0, y: 1, w: 2, h: 2, i: "3" },
38 | { x: 1, y: 1, w: 1, h: 1, i: "2" }
39 | ]);
40 | });
41 | });
42 |
43 | describe("collides", () => {
44 | it("Returns whether the layout items collide", () => {
45 | expect(
46 | collides(
47 | { i: "1", x: 0, y: 1, w: 1, h: 1 },
48 | { i: "2", x: 1, y: 2, w: 1, h: 1 }
49 | )
50 | ).toEqual(false);
51 | expect(
52 | collides(
53 | { i: "1", x: 0, y: 1, w: 1, h: 1 },
54 | { i: "2", x: 0, y: 1, w: 1, h: 1 }
55 | )
56 | ).toEqual(true);
57 | });
58 | });
59 |
60 | describe("validateLayout", () => {
61 | it("Validates an empty layout", () => {
62 | validateLayout([]);
63 | });
64 | it("Validates a populated layout", () => {
65 | validateLayout([
66 | { i: "1", x: 0, y: 1, w: 1, h: 1 },
67 | { i: "2", x: 1, y: 2, w: 1, h: 1 }
68 | ]);
69 | });
70 | it("Throws errors on invalid input", () => {
71 | expect(() => {
72 | validateLayout([
73 | { i: "1", x: 0, y: 1, w: 1, h: 1 },
74 | { i: "2", x: 1, y: 2, w: 1 }
75 | ]);
76 | }).toThrowError(/layout\[1\]\.h must be a number!/i);
77 | });
78 | });
79 |
80 | describe("moveElement", () => {
81 | function compactAndMove(
82 | layout,
83 | layoutItem,
84 | x,
85 | y,
86 | isUserAction,
87 | preventCollision
88 | ) {
89 | return compact(
90 | moveElement(
91 | layout,
92 | layoutItem,
93 | x,
94 | y,
95 | isUserAction,
96 | preventCollision
97 | )
98 | );
99 | }
100 |
101 | it("Does not change layout when colliding on no rearrangement mode", () => {
102 | const layout = [
103 | { i: "1", x: 0, y: 1, w: 1, h: 1, moved: false },
104 | { i: "2", x: 1, y: 2, w: 1, h: 1, moved: false }
105 | ];
106 | const layoutItem = layout[0];
107 | expect(
108 | moveElement(
109 | layout,
110 | layoutItem,
111 | 1,
112 | 2, // x, y
113 | true,
114 | true // isUserAction, preventCollision
115 | )
116 | ).toEqual([
117 | { i: "1", x: 0, y: 1, w: 1, h: 1, moved: false },
118 | { i: "2", x: 1, y: 2, w: 1, h: 1, moved: false }
119 | ]);
120 | });
121 |
122 | it("Does change layout when colliding in rearrangement mode", () => {
123 | const layout = [
124 | { i: "1", x: 0, y: 0, w: 1, h: 1, moved: false },
125 | { i: "2", x: 1, y: 0, w: 1, h: 1, moved: false }
126 | ];
127 | const layoutItem = layout[0];
128 | expect(
129 | moveElement(
130 | layout,
131 | layoutItem,
132 | 1,
133 | 0, // x, y
134 | true,
135 | false // isUserAction, preventCollision
136 | )
137 | ).toEqual([
138 | { i: "1", x: 1, y: 0, w: 1, h: 1, moved: true },
139 | { i: "2", x: 1, y: 1, w: 1, h: 1, moved: true }
140 | ]);
141 | });
142 |
143 | it("Moves elements out of the way without causing panel jumps when compaction is vertical", () => {
144 | const layout = [
145 | { x: 0, y: 0, w: 1, h: 10, i: "A" },
146 | { x: 0, y: 10, w: 1, h: 1, i: "B" },
147 | { x: 0, y: 11, w: 1, h: 1, i: "C" }
148 | ];
149 | // move A down slightly so it collides with C; can cause C to jump above B.
150 | // We instead want B to jump above A (it has the room)
151 | const itemA = layout[0];
152 | expect(
153 | compactAndMove(
154 | layout,
155 | itemA,
156 | 0,
157 | 1, // x, y
158 | true,
159 | false // isUserAction, preventCollision
160 | )
161 | ).toEqual([
162 | expect.objectContaining({ x: 0, y: 1, w: 1, h: 10, i: "A" }),
163 | expect.objectContaining({ x: 0, y: 0, w: 1, h: 1, i: "B" }),
164 | expect.objectContaining({ x: 0, y: 11, w: 1, h: 1, i: "C" })
165 | ]);
166 | });
167 |
168 | it("Calculates the correct collision when moving large object far", () => {
169 | const layout = [
170 | { x: 0, y: 0, w: 1, h: 10, i: "A" },
171 | { x: 0, y: 10, w: 1, h: 1, i: "B" },
172 | { x: 0, y: 11, w: 1, h: 1, i: "C" }
173 | ];
174 | // Move A down by 2. This should move B above, but since we don't compact in between,
175 | // C should move below.
176 | const itemA = layout[0];
177 | expect(
178 | moveElement(
179 | layout,
180 | itemA,
181 | 0,
182 | 2, // x, y
183 | true,
184 | false // isUserAction, preventCollision
185 | )
186 | ).toEqual([
187 | expect.objectContaining({ x: 0, y: 2, w: 1, h: 10, i: "A" }),
188 | expect.objectContaining({ x: 0, y: 1, w: 1, h: 1, i: "B" }),
189 | expect.objectContaining({ x: 0, y: 12, w: 1, h: 1, i: "C" })
190 | ]);
191 | });
192 |
193 | it("Moves elements out of the way without causing panel jumps when compaction is vertical", () => {
194 | const layout = [
195 | { x: 0, y: 0, w: 1, h: 1, i: "A" },
196 | { x: 1, y: 0, w: 1, h: 1, i: "B" },
197 | { x: 0, y: 1, w: 2, h: 2, i: "C" }
198 | ];
199 | // move A over slightly so it collides with B; can cause C to jump above B
200 | // this test will check that that does not happen
201 | const itemA = layout[0];
202 | expect(
203 | moveElement(
204 | layout,
205 | itemA,
206 | 1,
207 | 0, // x, y
208 | true,
209 | false // isUserAction, preventCollision
210 | )
211 | ).toEqual([
212 | { x: 1, y: 0, w: 1, h: 1, i: "A", moved: true },
213 | { x: 1, y: 1, w: 1, h: 1, i: "B", moved: true },
214 | { x: 0, y: 2, w: 2, h: 2, i: "C", moved: true }
215 | ]);
216 | });
217 |
218 | it("Moves one element to another should cause moving down panels, vert compact", () => {
219 | // | A | B |
220 | // |C| D |
221 | const layout = [
222 | { x: 0, y: 0, w: 2, h: 1, i: "A" },
223 | { x: 2, y: 0, w: 2, h: 1, i: "B" },
224 | { x: 0, y: 1, w: 1, h: 1, i: "C" },
225 | { x: 1, y: 1, w: 3, h: 1, i: "D" }
226 | ];
227 | // move B left slightly so it collides with A; can cause C to jump above A
228 | // this test will check that that does not happen
229 | const itemB = layout[1];
230 | expect(
231 | compactAndMove(
232 | layout,
233 | itemB,
234 | 1,
235 | 0, // x, y
236 | true,
237 | false // isUserAction, preventCollision
238 | )
239 | ).toEqual([
240 | expect.objectContaining({ x: 0, y: 1, w: 2, h: 1, i: "A" }),
241 | expect.objectContaining({ x: 1, y: 0, w: 2, h: 1, i: "B" }),
242 | expect.objectContaining({ x: 0, y: 2, w: 1, h: 1, i: "C" }),
243 | expect.objectContaining({ x: 1, y: 2, w: 3, h: 1, i: "D" })
244 | ]);
245 | });
246 |
247 | it("Moves one element to another should cause moving down panels, vert compact", () => {
248 | // | A |
249 | // |B|C|
250 | // | |
251 | //
252 | // Moving C above A should not move B above A
253 | const layout = [
254 | { x: 0, y: 0, w: 2, h: 1, i: "A" },
255 | { x: 0, y: 1, w: 1, h: 1, i: "B" },
256 | { x: 1, y: 1, w: 1, h: 2, i: "C" }
257 | ];
258 | // Move C up.
259 | const itemB = layout[2];
260 | expect(
261 | compactAndMove(
262 | layout,
263 | itemB,
264 | 1,
265 | 0, // x, y
266 | true,
267 | false // isUserAction, preventCollision
268 | )
269 | ).toEqual([
270 | expect.objectContaining({ x: 0, y: 2, w: 2, h: 1, i: "A" }),
271 | expect.objectContaining({ x: 0, y: 3, w: 1, h: 1, i: "B" }),
272 | expect.objectContaining({ x: 1, y: 0, w: 1, h: 2, i: "C" })
273 | ]);
274 | });
275 | });
276 |
277 | describe("compact vertical", () => {
278 | it("Removes empty vertical space above item", () => {
279 | const layout = [{ i: "1", x: 0, y: 1, w: 1, h: 1 }];
280 | expect(compact(layout, true)).toEqual([
281 | { i: "1", x: 0, y: 0, w: 1, h: 1, moved: false }
282 | ]);
283 | });
284 |
285 | it("Resolve collision by moving item further down in array", () => {
286 | const layout = [
287 | { x: 0, y: 0, w: 1, h: 5, i: "1" },
288 | { x: 0, y: 1, w: 1, h: 1, i: "2" }
289 | ];
290 | expect(compact(layout, true)).toEqual([
291 | { x: 0, y: 0, w: 1, h: 5, i: "1", moved: false },
292 | { x: 0, y: 5, w: 1, h: 1, i: "2", moved: false }
293 | ]);
294 | });
295 |
296 | it("Handles recursive collision by moving new collisions out of the way before moving item down", () => {
297 | const layout = [
298 | { x: 0, y: 0, w: 2, h: 5, i: "1" },
299 | { x: 0, y: 0, w: 10, h: 1, i: "2" },
300 | { x: 5, y: 1, w: 1, h: 1, i: "3" },
301 | { x: 5, y: 2, w: 1, h: 1, i: "4" },
302 | { x: 5, y: 3, w: 1, h: 1, i: "5", static: true }
303 | ];
304 |
305 | expect(compact(layout, true)).toEqual([
306 | { x: 0, y: 0, w: 2, h: 5, i: "1", moved: false },
307 | { x: 0, y: 5, w: 10, h: 1, i: "2", moved: false },
308 | { x: 5, y: 0, w: 1, h: 1, i: "3", moved: false },
309 | { x: 5, y: 1, w: 1, h: 1, i: "4", moved: false },
310 | { x: 5, y: 3, w: 1, h: 1, i: "5", moved: false, static: true }
311 | ]);
312 | });
313 | });
314 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'node:url';
2 | import { resolve } from 'path';
3 | import { defineConfig } from 'vite';
4 | import vue from '@vitejs/plugin-vue';
5 | import vueJsx from '@vitejs/plugin-vue-jsx';
6 | import { libInjectCss } from 'vite-plugin-lib-inject-css';
7 | import eslint from '@rollup/plugin-eslint';
8 | import pkg from './package.json';
9 |
10 | function banner() {
11 | return {
12 | name: 'banner',
13 | enforce: 'post',
14 | generateBundle(options, bundle) {
15 | const banner = `/**\n * ${pkg.name} ${pkg.version}\n`
16 | + ` * ${pkg.author}\n * ${pkg.homepage}\n */\n`;
17 |
18 | for (const module of Object.values(bundle)) {
19 | if (module.type === 'chunk') {
20 | module.code = banner + module.code;
21 | }
22 | }
23 | },
24 | };
25 | }
26 |
27 | // https://vitejs.dev/config/
28 | export default defineConfig(() => ({
29 | plugins: [
30 | vue(),
31 | vueJsx(),
32 | eslint({
33 | include: ['./src/**/*.js', './src/**/*.vue'],
34 | }),
35 | libInjectCss(),
36 | banner(),
37 | ],
38 | resolve: {
39 | alias: {
40 | '@': fileURLToPath(new URL('./src', import.meta.url)),
41 | },
42 | },
43 | build: {
44 | lib: {
45 | // Could also be a dictionary or array of multiple entry points
46 | entry: resolve(__dirname, 'src/components/index.js'),
47 | name: 'VueGridLayout',
48 | // the proper extensions will be added
49 | fileName: 'vue-grid-layout-v3',
50 | formats: ['iife', 'es', 'umd', 'cjs'],
51 | },
52 | rollupOptions: {
53 | // 确保外部化处理那些你不想打包进库的依赖
54 | external: ['vue'],
55 | output: [{
56 | format: 'es',
57 | // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
58 | // globals: { vue: 'Vue' },
59 | }, {
60 | name: 'VueGridLayout',
61 | format: 'iife',
62 | exports: 'named',
63 | // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
64 | globals: { vue: 'Vue' },
65 | }, {
66 | name: 'VueGridLayout',
67 | entryFileNames: 'vue-grid-layout-v3.umd.js',
68 | format: 'umd',
69 | exports: 'named',
70 | // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
71 | globals: { vue: 'Vue' },
72 | }, {
73 | format: 'cjs',
74 | exports: 'named',
75 | // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
76 | globals: { vue: 'Vue' },
77 | }],
78 | },
79 | },
80 | }));
81 |
--------------------------------------------------------------------------------
/website/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 4
4 | end_of_line = lf
5 | trim_trailing_whitespace = true
6 | insert_final_newline = true
7 | max_line_length = 100
8 |
--------------------------------------------------------------------------------
/website/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | const config = {
3 | root: true,
4 | extends: [
5 | 'plugin:vue/vue3-essential',
6 | 'eslint:recommended',
7 | 'airbnb-base',
8 | ],
9 | // env: {
10 | // // 'vue/setup-compiler-macros': true,
11 | // es6: true,
12 | // },
13 | // parserOptions: {
14 | // },
15 | parser: 'vue-eslint-parser',
16 | parserOptions: {
17 | ecmaVersion: 'latest',
18 | // parser: '@babel/eslint-parser',
19 | ecmaFeatures: {
20 | jsx: true,
21 | },
22 | },
23 | rules: {
24 | // 修改的规则
25 | 'no-multi-spaces': [2, { ignoreEOLComments: true }],
26 | indent: [2, 4, { SwitchCase: 1 }],
27 | 'vue/html-indent': [2, 4],
28 |
29 | // 关闭vue的规则
30 | 'vue/multi-word-component-names': 0,
31 | 'vue/require-component-is': 0,
32 | 'vue/no-v-for-template-key-on-child': 0,
33 | 'vue/no-v-text-v-html-on-component': 0,
34 |
35 | // 关闭import规则
36 | 'import/extensions': 0,
37 | 'import/no-extraneous-dependencies': 0,
38 | 'import/no-dynamic-require': 0,
39 | 'import/no-unresolved': 0,
40 | 'import/prefer-default-export': 0,
41 |
42 | // 关闭airbnb规则
43 | 'arrow-parens': 0,
44 | 'arrow-body-style': 0,
45 | 'consistent-return': 0,
46 | 'default-param-last': 0,
47 | 'default-case': 0,
48 | 'global-require': 0,
49 | 'object-curly-newline': 0,
50 | 'prefer-destructuring': 0,
51 | radix: 0,
52 | 'max-len': 0,
53 | 'newline-per-chained-call': 0,
54 | 'no-bitwise': 0,
55 | 'no-console': 0,
56 | 'no-control-regex': 0,
57 | 'no-cond-assign': 0,
58 | 'no-continue': 0,
59 | 'no-lonely-if': 0,
60 | 'no-return-assign': 0,
61 | 'no-restricted-syntax': 0,
62 | 'no-param-reassign': 0,
63 | 'no-plusplus': 0,
64 | 'no-use-before-define': 0,
65 | 'no-multiple-empty-lines': 0,
66 | 'no-shadow': 0,
67 |
68 | // 关闭其他规则
69 | 'prettier/prettier': 0,
70 | camelcase: 0,
71 |
72 | // 增加的规则
73 | 'no-debugger': 2,
74 | },
75 | ignorePatterns: [
76 | 'public/**',
77 | 'dist/**',
78 | ],
79 | };
80 |
81 | // 开发测试阶段降低规则要求
82 | if (process.env.NODE_ENV !== 'production') {
83 | Object.assign(config.rules, {
84 | 'vue/no-unused-vars': 1,
85 | 'vue/valid-template-root': 1,
86 | 'vue/return-in-computed-property': 1,
87 | 'vue/valid-v-for': 1,
88 |
89 | 'import/newline-after-import': 1,
90 |
91 | 'array-bracket-spacing': 1,
92 | 'brace-style': 1,
93 | 'block-spacing': 1,
94 | 'comma-dangle': 1,
95 | 'comma-spacing': 1,
96 | indent: [1, 4, { SwitchCase: 1 }],
97 | 'key-spacing': 1,
98 | 'keyword-spacing': 1,
99 | 'operator-linebreak': 1,
100 | 'prefer-const': 1,
101 | 'padded-blocks': 1,
102 | 'quote-props': 1,
103 | semi: 1,
104 | 'spaced-comment': 1,
105 | 'space-before-blocks': 1,
106 | 'space-before-function-paren': 1,
107 | 'space-infix-ops': 1,
108 | 'space-in-parens': 1,
109 | 'no-debugger': 1,
110 | 'no-empty': 1,
111 | 'no-empty-function': 1,
112 | 'no-unused-vars': 1,
113 | 'no-multi-spaces': [1, { ignoreEOLComments: true }],
114 | 'no-unreachable': 1,
115 | });
116 | }
117 |
118 | module.exports = config;
119 |
120 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | #/dist
4 | dist/
5 | cache/
6 |
7 | # local env files
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw*
24 |
25 | yarn-error.log
26 |
27 | .vitepress/cache/
28 |
--------------------------------------------------------------------------------
/website/.vitepress/config.mjs:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'node:url';
2 | import { defineConfig } from 'vitepress'
3 |
4 | // https://vitepress.dev/reference/site-config
5 | export default defineConfig({
6 | srcDir: 'src',
7 | title: "Vue3 Grid Layout",
8 | description: "A draggable and resizable grid layout, as a Vue component.",
9 | markdown: {
10 | theme: 'monokai',
11 | lineNumbers: true,
12 | },
13 | cleanUrls: true,
14 | base: "/vue-grid-layout-v3/",
15 | vite: {
16 | resolve: {
17 | alias: {
18 | '@': fileURLToPath(new URL('../src/', import.meta.url)),
19 | },
20 | },
21 | ssr: {
22 | noExternal: ['vue-grid-layout-v3'],
23 | },
24 | },
25 | themeConfig: {
26 | // https://vitepress.dev/reference/default-theme-config
27 | logo: '/logo.png',
28 | repo: 'merfais/vue-grid-layout-v3',
29 | head: [
30 | ['link', { rel: 'icon', href: '/favicon.ico' }],
31 | ],
32 | nav: [
33 | { text: 'Home', link: '/' },
34 | { text: 'Guide', link: '/guide/' }
35 | ],
36 | sidebar: [
37 | {
38 | text: 'Guide',
39 | items: [
40 | { text: 'Installation', link: '/guide/' },
41 | { text: 'Usage', link: '/guide/usage' },
42 | { text: 'Properties', link: '/guide/properties' },
43 | { text: 'Events', link: '/guide/events' },
44 | { text: 'Styling', link: '/guide/styling' },
45 | ]
46 | },
47 | {
48 | text: 'Examples',
49 | items: [
50 | { text: '01 - Basic', link: '/guide/01-basic' },
51 | { text: '02 - Move and resize events', link: '/guide/02-events' },
52 | { text: '03 - Multiple grids', link: '/guide/03-multiple-grids' },
53 | { text: '04 - Drag allow/ignore elements', link: '/guide/04-allow-ignore' },
54 | { text: '05 - Mirrored grid layout', link: '/guide/05-mirrored' },
55 | { text: '06 - Responsive', link: '/guide/06-responsive' },
56 | { text: '07 - Prevent Collision', link: '/guide/07-prevent-collision' },
57 | { text: '08 - Responsive with predefined layouts', link: '/guide/08-responsive-predefined-layouts' },
58 | { text: '09 - Dynamic Add/Remove', link: '/guide/09-dynamic-add-remove' },
59 | { text: '10 - Drag From Outside', link: '/guide/10-drag-from-outside' },
60 | { text: '11 - Dragging grid items bounded to grid container', link: '/guide/11-bounded' },
61 | ]
62 | }
63 | ],
64 | aside: false,
65 | socialLinks: [
66 | { icon: 'github', link: 'https://github.com/merfais/vue-grid-layout-v3' }
67 | ],
68 | search: {
69 | provider: 'local',
70 | // options: {
71 | // appId: 'vue_grid_layout',
72 | // apiKey: '2f143d1edd24605564065dd02bf0a22b',
73 | // indexName: 'vue_grid_layout'
74 | // }
75 | },
76 | editLink: {
77 | pattern: 'https://github.com/merfais/vue-grid-layout-v3/tree/master/website/src/:path',
78 | text: 'Edit this page on GitHub'
79 | },
80 | lastUpdated: {
81 | text: 'Updated at',
82 | formatOptions: {
83 | dateStyle: 'full',
84 | timeStyle: 'medium'
85 | }
86 | },
87 | externalLinkIcon: true,
88 | }
89 | })
90 |
--------------------------------------------------------------------------------
/website/.vitepress/theme/custom.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --vp-button-brand-bg: #3eaf7c;
3 | }
4 |
--------------------------------------------------------------------------------
/website/.vitepress/theme/index.js:
--------------------------------------------------------------------------------
1 | // https://vitepress.dev/guide/custom-theme
2 | import DefaultTheme from 'vitepress/theme'
3 | import './style.css'
4 |
5 | /** @type {import('vitepress').Theme} */
6 | export default {
7 | extends: DefaultTheme,
8 | // Layout: () => {
9 | // return h(DefaultTheme.Layout, null, {
10 | // // https://vitepress.dev/guide/extending-default-theme#layout-slots
11 | // })
12 | // },
13 | enhanceApp({ app, router, siteData }) {
14 | // ...
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/website/.vitepress/theme/style.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Customize default theme styling by overriding CSS variables:
3 | * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
4 | */
5 |
6 | /**
7 | * Colors
8 | *
9 | * Each colors have exact same color scale system with 3 levels of solid
10 | * colors with different brightness, and 1 soft color.
11 | *
12 | * - `XXX-1`: The most solid color used mainly for colored text. It must
13 | * satisfy the contrast ratio against when used on top of `XXX-soft`.
14 | *
15 | * - `XXX-2`: The color used mainly for hover state of the button.
16 | *
17 | * - `XXX-3`: The color for solid background, such as bg color of the button.
18 | * It must satisfy the contrast ratio with pure white (#ffffff) text on
19 | * top of it.
20 | *
21 | * - `XXX-soft`: The color used for subtle background such as custom container
22 | * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
23 | * on top of it.
24 | *
25 | * The soft color must be semi transparent alpha channel. This is crucial
26 | * because it allows adding multiple "soft" colors on top of each other
27 | * to create a accent, such as when having inline code block inside
28 | * custom containers.
29 | *
30 | * - `default`: The color used purely for subtle indication without any
31 | * special meanings attched to it such as bg color for menu hover state.
32 | *
33 | * - `brand`: Used for primary brand colors, such as link text, button with
34 | * brand theme, etc.
35 | *
36 | * - `tip`: Used to indicate useful information. The default theme uses the
37 | * brand color for this by default.
38 | *
39 | * - `warning`: Used to indicate warning to the users. Used in custom
40 | * container, badges, etc.
41 | *
42 | * - `danger`: Used to show error, or dangerous message to the users. Used
43 | * in custom container, badges, etc.
44 | * -------------------------------------------------------------------------- */
45 |
46 | :root {
47 | --vp-c-brand-1: var(--vp-c-green-1);
48 | --vp-c-brand-2: var(--vp-c-green-2);
49 | --vp-c-brand-3: var(--vp-c-green-3);
50 | --vp-c-brand-soft: var(--vp-c-green-soft);
51 |
52 | --vp-code-block-color: rgba(255, 255, 245, 0.86);
53 | --vp-code-block-bg: rgb(39, 40, 34);
54 | --vp-code-block-divider-color: #000000;
55 |
56 | --vp-code-lang-color: rgba(235, 235, 245, 0.38);
57 |
58 | --vp-code-line-highlight-color: #000000;
59 | --vp-code-line-number-color: rgba(235, 235, 245, 0.38);
60 |
61 | --vp-code-copy-code-border-color: rgba(82, 82, 89, 0.32);
62 | --vp-code-copy-code-bg: #252529;
63 | --vp-code-copy-code-hover-border-color: rgba(82, 82, 89, 0.32);
64 | --vp-code-copy-code-hover-bg: #323238;
65 | --vp-code-copy-code-active-text: rgba(255, 255, 245, 0.86);
66 |
67 | --vp-code-tab-text-color: rgba(235, 235, 245, 0.6);
68 | --vp-code-tab-hover-text-color: rgba(255, 255, 245, 0.86);
69 | --vp-code-tab-active-text-color: rgba(255, 255, 245, 0.86);
70 | }
71 |
72 | /**
73 | * Component: Button
74 |
75 | :root {
76 | --vp-button-brand-border: transparent;
77 | --vp-button-brand-text: var(--vp-c-white);
78 | --vp-button-brand-bg: var(--vp-c-brand-3);
79 | --vp-button-brand-hover-border: transparent;
80 | --vp-button-brand-hover-text: var(--vp-c-white);
81 | --vp-button-brand-hover-bg: var(--vp-c-brand-2);
82 | --vp-button-brand-active-border: transparent;
83 | --vp-button-brand-active-text: var(--vp-c-white);
84 | --vp-button-brand-active-bg: var(--vp-c-brand-1);
85 | }
86 | * -------------------------------------------------------------------------- */
87 |
88 | /**
89 | * Component: Home
90 | * -------------------------------------------------------------------------- */
91 | :root {
92 | --vp-home-hero-name-color: transparent;
93 | --vp-home-hero-name-background: linear-gradient(
94 | 120deg,
95 | #3eaf7c 30%,
96 | #41d1ff
97 | );
98 |
99 | --vp-home-hero-image-background-image: linear-gradient(
100 | 45deg,
101 | #bd34fe 50%,
102 | #47caff 50%
103 | );
104 | --vp-home-hero-image-filter: blur(44px);
105 |
106 | }
107 |
108 | @media (min-width: 640px) {
109 | :root {
110 | --vp-home-hero-image-filter: blur(56px);
111 | }
112 | }
113 |
114 | @media (min-width: 960px) {
115 | :root {
116 | --vp-home-hero-image-filter: blur(68px);
117 | }
118 | }
119 |
120 |
121 |
--------------------------------------------------------------------------------
/website/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merfais/vue-grid-layout-v3/a669942fa85c80211767b89acddbe6211319ffe2/website/favicon.ico
--------------------------------------------------------------------------------
/website/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vue Grid Layout
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/website/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-grid-layout-website",
3 | "version": "1.0.0",
4 | "description": "vue-grid-layout website",
5 | "author": "coffeebi (merfais.bwq@163.com)",
6 | "license": "MIT",
7 | "private": false,
8 | "scripts": {
9 | "dev": "vite",
10 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs",
11 | "lint:fix": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix",
12 | "docs:dev": "vitepress dev",
13 | "docs:build": "vitepress build",
14 | "docs:preview": "vitepress preview"
15 | },
16 | "devDependencies": {
17 | "@rollup/plugin-eslint": "^9.0.5",
18 | "eslint": "^8.57.0",
19 | "eslint-config-airbnb-base": "^15.0.0",
20 | "eslint-plugin-vue": "^9.23.0",
21 | "vite": "^5.3.1",
22 | "vitepress": "^1.3.4",
23 | "vitepress-plugin-back-to-top": "^1.0.1",
24 | "vitepress-plugin-google-analytics": "^1.0.2",
25 | "vue-eslint-parser": "^9.4.3"
26 | },
27 | "resolutions": {},
28 | "dependencies": {
29 | "vue": "^3.5.11",
30 | "vue-grid-layout-v3": "^3.1.2-rc.1"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/website/src/app.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
31 |
32 |
{{index + 1}} - {{item.__file}}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
60 |
--------------------------------------------------------------------------------
/website/src/example/01-basic.vue:
--------------------------------------------------------------------------------
1 |
41 |
42 |
51 |
61 | {{itemTitle(item)}}
62 |
63 |
64 |
65 |
93 |
--------------------------------------------------------------------------------
/website/src/example/02-events.vue:
--------------------------------------------------------------------------------
1 |
101 |
102 |
103 |
104 |
105 | {{event}}
106 |
107 |
108 |
109 |
123 |
137 | {{item.i}}
138 |
139 |
140 |
141 |
142 |
143 |
179 |
--------------------------------------------------------------------------------
/website/src/example/03-multiple-grids.vue:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
Grid #1
22 |
31 |
40 | {{item.i}}
41 |
42 |
43 |
44 |
45 |
Grid #2
46 |
55 |
64 | {{item.i}}
65 |
66 |
67 |
68 |
69 |
70 |
94 |
--------------------------------------------------------------------------------
/website/src/example/04-allow-ignore.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
41 |
52 |
53 |
54 |
55 | {{item.i}}
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
114 |
--------------------------------------------------------------------------------
/website/src/example/05-mirrored.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 | Draggable
36 | Resizable
37 | Mirrored
38 |
39 |
49 |
59 | {{item.i}}
60 |
61 |
62 |
63 |
64 |
92 |
--------------------------------------------------------------------------------
/website/src/example/06-responsive.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 | Displayed as
[x, y, w, h]
:
37 |
38 |
39 | {{item.i}}: [{{item.x}}, {{item.y}}, {{item.w}}, {{item.h}}]
40 |
41 |
42 |
43 |
44 |
Draggable
45 |
Resizable
46 |
Responsive
47 |
48 |
49 |
59 |
69 | {{item.i}}
70 |
71 |
72 |
73 |
74 |
75 |
110 |
--------------------------------------------------------------------------------
/website/src/example/07-prevent-collision.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
43 |
53 | {{item.i}}
54 |
55 |
56 |
57 |
58 |
86 |
--------------------------------------------------------------------------------
/website/src/example/08-responsive-predefined-layouts.vue:
--------------------------------------------------------------------------------
1 |
63 |
64 |
65 |
66 |
78 |
87 | {{item.i}}
88 |
89 |
90 |
91 |
92 |
116 |
--------------------------------------------------------------------------------
/website/src/example/09-dynamic-add-remove.vue:
--------------------------------------------------------------------------------
1 |
37 |
38 |
39 |
40 | Displayed as
[x, y, w, h]
:
41 |
42 |
43 | {{item.i}}: [{{item.x}}, {{item.y}}, {{item.w}}, {{item.h}}]
44 |
45 |
46 |
47 |
48 |
49 | Draggable
50 | Resizable
51 |
52 |
61 |
71 | {{item.i}}
72 | x
73 |
74 |
75 |
76 |
77 |
133 |
--------------------------------------------------------------------------------
/website/src/example/10-drag-from-outside.vue:
--------------------------------------------------------------------------------
1 |
101 |
102 |
103 |
104 |
105 | Displayed as
[x, y, w, h]
:
106 |
107 |
108 | {{ item.i }}: [{{ item.x }}, {{ item.y }}, {{ item.w }}, {{ item.h }}]
109 |
110 |
111 |
112 |
113 |
114 |
Droppable Element (Drag me!)
116 |
117 |
127 |
137 | {{ item.i }}
138 |
139 |
140 |
141 |
142 |
143 |
189 |
--------------------------------------------------------------------------------
/website/src/example/11-bounded.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 | Displayed as
[x, y, w, h]
:
37 |
38 |
39 | {{item.i}}: [{{item.x}}, {{item.y}}, {{item.w}}, {{item.h}}]
40 |
41 |
42 |
43 |
44 |
Draggable
45 |
Resizable
46 |
Bounded
47 |
48 |
49 |
59 |
69 | {{item.i}}
70 |
71 |
72 |
73 |
74 |
75 |
110 |
--------------------------------------------------------------------------------
/website/src/example/dom.js:
--------------------------------------------------------------------------------
1 | // let currentDir: "ltr" | "rtl" | "auto" = "auto";
2 | let currentDir = 'auto';
3 |
4 | function hasDocument() {
5 | return (typeof document !== 'undefined');
6 | }
7 |
8 | function hasWindow() {
9 | return (typeof window !== 'undefined');
10 | }
11 |
12 | export function getDocumentDir() {
13 | if (!hasDocument()) {
14 | return currentDir;
15 | }
16 | const direction = (typeof document.dir !== 'undefined')
17 | ? document.dir
18 | : document.getElementsByTagName('html')[0].getAttribute('dir');
19 | return direction;
20 | }
21 |
22 | // export function setDocumentDir(dir: "ltr" | "rtl" | "auto"){
23 | export function setDocumentDir(dir) {
24 | if (!hasDocument) {
25 | currentDir = dir;
26 | return;
27 | }
28 |
29 | const html = document.getElementsByTagName('html')[0];
30 | html.setAttribute('dir', dir);
31 | }
32 |
33 | const cb = () => {};
34 | // export function addWindowEventListener(event:string, callback: () => mixed){
35 | export function addWindowEventListener(event, callback = cb) {
36 | if (!hasWindow) {
37 | callback();
38 | return;
39 | }
40 | window.addEventListener(event, callback);
41 | }
42 |
43 | export function removeWindowEventListener(event, callback = cb) {
44 | if (!hasWindow) {
45 | return;
46 | }
47 | window.removeEventListener(event, callback);
48 | }
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/website/src/example/styling-grid-lines.vue:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 |
45 |
56 |
66 | {{ itemTitle(item) }}
67 |
68 |
69 |
70 |
71 |
114 |
--------------------------------------------------------------------------------
/website/src/example/styling-placeholder.vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
51 |
61 | {{itemTitle(item)}}
62 |
63 |
64 |
65 |
66 |
96 |
--------------------------------------------------------------------------------
/website/src/example/test-element.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 | {{text}}
24 |
25 | x
26 |
27 |
28 |
36 |
37 |
--------------------------------------------------------------------------------
/website/src/example/usage.vue:
--------------------------------------------------------------------------------
1 |
180 |
181 |
182 |
183 |
184 | {{item.i}}:{{item}}
185 |
186 |
187 |
210 |
234 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
328 |
--------------------------------------------------------------------------------
/website/src/guide/01-basic.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 01 - Basic
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/01-basic.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/01-basic.vue)
14 |
15 |
16 |
--------------------------------------------------------------------------------
/website/src/guide/02-events.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 02 - Move and resize events
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/02-events.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/02-events.vue)
14 |
15 |
--------------------------------------------------------------------------------
/website/src/guide/03-multiple-grids.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 03 - Multiple grids
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/03-multiple-grids.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/03-multiple-grids.vue)
14 |
15 |
--------------------------------------------------------------------------------
/website/src/guide/04-allow-ignore.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 04 - Drag allow/ignore elements
6 |
7 | Ignore drag on certain elements and allow on others.
8 |
9 | Click and drag the dots on the corner of each item to reposition
10 |
11 |
12 |
13 |
14 |
15 | <<< @/example/04-allow-ignore.vue
16 |
17 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/04-allow-ignore.vue)
18 |
19 |
--------------------------------------------------------------------------------
/website/src/guide/05-mirrored.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 05 - Mirrored grid layout
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/05-mirrored.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/05-mirrored.vue)
14 |
15 |
--------------------------------------------------------------------------------
/website/src/guide/06-responsive.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 06 - Responsive
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/06-responsive.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/06-responsive.vue)
14 |
15 |
--------------------------------------------------------------------------------
/website/src/guide/07-prevent-collision.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 07 - Prevent Collision
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/07-prevent-collision.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/07-prevent-collision.vue)
14 |
--------------------------------------------------------------------------------
/website/src/guide/08-responsive-predefined-layouts.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 08 - Responsive with predefined layouts
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/08-responsive-predefined-layouts.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/08-responsive-predefined-layouts.vue)
14 |
15 |
--------------------------------------------------------------------------------
/website/src/guide/09-dynamic-add-remove.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 09 - Dynamic Add/Remove
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/09-dynamic-add-remove.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/09-dynamic-add-remove.vue)
14 |
15 |
--------------------------------------------------------------------------------
/website/src/guide/10-drag-from-outside.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 10 - Drag From Outside
6 |
7 | This demo shows what happens when an item is added from outside of the grid.
8 |
9 | Once you drop the item within the grid you'll get its coordinates/properties and can perform actions with it accordingly.
10 |
11 |
12 |
13 |
14 |
15 | <<< @/example/10-drag-from-outside.vue
16 |
17 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/10-drag-from-outside.vue)
18 |
19 |
--------------------------------------------------------------------------------
/website/src/guide/11-bounded.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # 11 - Dragging grid items bounded to grid container
6 |
7 |
8 |
9 |
10 |
11 | <<< @/example/11-bounded.vue
12 |
13 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/11-bounded.vue)
14 |
15 |
--------------------------------------------------------------------------------
/website/src/guide/auto-size.md:
--------------------------------------------------------------------------------
1 | # Auto Sizing Grid Items
2 |
3 | TODO: https://github.com/merfais/vue-grid-layout-v3/issues/351
4 |
--------------------------------------------------------------------------------
/website/src/guide/events.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: true
3 | ---
4 | # Events
5 |
6 | Move and resize event listeners can be added to each grid-item, so that the parent Vue can be notified when a grid element is being moved or resized.
7 | Moved and resized event listeners can be added, if the only notification needed is when an item is finished moving or resizing.
8 |
9 | Working example [here](../guide/02-events.md)
10 |
11 | ````html
12 |
26 |
40 | {{item.i}}
41 |
42 |
43 | ````
44 |
45 | ## GridLayout
46 |
47 | ### update:layout
48 |
49 | sync layout by v-model:layout. same as layout-updated
50 |
51 | ```html
52 |
55 |
56 |
57 | ```
58 | ### layout-created
59 |
60 | Layout created event
61 |
62 | Emited on the component created lifecycle hook
63 |
64 | ```javascript
65 | function layoutCreatedEvent(newLayout){
66 | console.log("Created layout: ", newLayout)
67 | }
68 | ```
69 |
70 | ### layout-before-mount
71 |
72 | Layout beforeMount event
73 |
74 | Emited on the component beforeMount lifecycle hook
75 |
76 | ```javascript
77 | function layoutBeforeMountEvent(newLayout){
78 | console.log("beforeMount layout: ", newLayout)
79 | }
80 | ```
81 |
82 | ### layout-mounted
83 |
84 | Layout mounted event
85 |
86 | Emited on the component mounted lifecycle hook
87 |
88 | ```javascript
89 | function layoutMountedEvent(newLayout){
90 | console.log("Mounted layout: ", newLayout)
91 | }
92 | ```
93 |
94 | ### layout-ready
95 |
96 | Layout ready event
97 |
98 | Emited when all the operations on the mount hook finish
99 |
100 | ```javascript
101 | function layoutReadyEvent(newLayout){
102 | console.log("Ready layout: ", newLayout)
103 | }
104 | ```
105 |
106 | ### layout-updated
107 |
108 | Layout updated event
109 |
110 | Every time the layout has finished updating and positions of all grid-items are recalculated
111 |
112 | ```javascript
113 | function layoutUpdatedEvent(newLayout){
114 | console.log("Updated layout: ", newLayout)
115 | }
116 | ```
117 |
118 |
119 | ### breakpoint-changed
120 |
121 | Breakpoint Changed event
122 |
123 | Every time the breakpoint value changes due to window resize
124 |
125 | ```javascript
126 | /**
127 | *
128 | * @param newBreakpoint the breakpoint name
129 | * @param newLayout the chosen layout for the breakpoint
130 | *
131 | */
132 | function breakpointChangedEvent(newBreakpoint, newLayout){
133 | console.log("BREAKPOINT CHANGED breakpoint=", newBreakpoint, ", layout: ", newLayout );
134 | },
135 | ```
136 |
137 |
138 | ## GridItem
139 |
140 | ### move
141 |
142 | Move event
143 |
144 | Every time an item is being moved and changes position
145 |
146 | ```javascript
147 | function moveEvent(i, newX, newY){
148 | console.log("MOVE i=" + i + ", X=" + newX + ", Y=" + newY);
149 | },
150 | ```
151 |
152 | ### moved
153 |
154 | Moved event
155 |
156 | Every time an item is finished being moved and changes position
157 |
158 | ```javascript
159 | function movedEvent(i, newX, newY){
160 | console.log("MOVED i=" + i + ", X=" + newX + ", Y=" + newY);
161 | },
162 | ```
163 |
164 | ### resize
165 |
166 | Resize event
167 |
168 | Every time an item is being resized and changes size
169 |
170 | ```javascript
171 | function resizeEvent(i, newH, newW, newHPx, newWPx){
172 | console.log("RESIZE i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
173 | },
174 | ```
175 |
176 | ### resized
177 |
178 | Resized event
179 |
180 | Every time an item is finished being resized and changes size
181 |
182 | ```javascript
183 | /**
184 | *
185 | * @param i the item id/index
186 | * @param newH new height in grid rows
187 | * @param newW new width in grid columns
188 | * @param newHPx new height in pixels
189 | * @param newWPx new width in pixels
190 | *
191 | */
192 | function resizedEvent(i, newH, newW, newHPx, newWPx){
193 | console.log("RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
194 | },
195 | ```
196 |
197 | ### container-resized
198 |
199 | Container Resized event
200 |
201 | Every time the grid item/layout container changes size (browser window or other)
202 |
203 | ```javascript
204 | /**
205 | *
206 | * @param i the item id/index
207 | * @param newH new height in grid rows
208 | * @param newW new width in grid columns
209 | * @param newHPx new height in pixels
210 | * @param newWPx new width in pixels
211 | *
212 | */
213 | function containerResizedEvent(i, newH, newW, newHPx, newWPx){
214 | console.log("CONTAINER RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
215 | },
216 | ```
217 |
218 |
--------------------------------------------------------------------------------
/website/src/guide/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: true
3 | ---
4 | # Installation
5 |
6 | ## NPM
7 |
8 | ```shell
9 | npm install vue-grid-layout-v3 --save
10 | ```
11 |
12 | ## Yarn
13 |
14 | ```shell
15 | yarn add vue-grid-layout-v3
16 | ```
17 |
18 |
19 | # Import the library
20 |
21 | ## Global Registration
22 |
23 | ```javascript
24 | import { createApp } from 'vue'
25 | import VueGridLayout from 'vue-grid-layout-v3';
26 |
27 | const app = createApp({
28 | // ...
29 | })
30 | // register GridLayout and GridItem component
31 | app.use(VueGridLayout)
32 | app.mount('#app')
33 |
34 | /**
35 | * // custom component name
36 | * import { createApp } from 'vue'
37 | * import { GridLayout, GridItem } from 'vue-grid-layout-v3';
38 | *
39 | * const app = createApp({
40 | * // ...
41 | * })
42 | * app.component('MyGridLayout', GridLayout)
43 | * app.component('MyGridItem', GridLayout)
44 | * app.mount('#app')
45 | */
46 |
47 | ```
48 |
49 | ## Local Registration
50 | When using SFC with `
56 |
57 |
58 |
59 |
60 |
61 |
62 | ```
63 | In non-`
87 |
88 |
89 |
90 |
91 |
101 | {{itemTitle(item)}}
102 |
103 |
104 |
105 |
106 |
156 | ```
157 |
158 |
--------------------------------------------------------------------------------
/website/src/guide/properties.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: true
3 | ---
4 | # Properties
5 |
6 | ## GridLayout
7 |
8 | ### layout
9 |
10 |
11 | * type: `Array`
12 | * required: `true`
13 |
14 | This is the initial layout of the grid.
15 |
16 | The value must be an `Array` of `Object` items. Each item must have `i`, `x`, `y`, `w` and `h` properties. Please refer to the documentation for `GridItem` below for more information.
17 |
18 | ### responsiveLayouts
19 |
20 | * type: `Object`
21 | * required: `false`
22 | * default : `{}`
23 |
24 | This is the initial layouts of the grid per breakpoint if `responsive` is set to `true`.
25 | The keys of the `Object` are breakpoint names and each value is an `Array` of `Object` items as defined by `layout` prop. eg:{ lg:[layout items], md:[layout items] }.
26 | Setting the prop after the creation of the GridLayout has no effect.
27 |
28 | See also [responsive](#responsive), [breakpoints](#breakpoints) and [cols](#cols)
29 |
30 | ### colNum
31 |
32 | * type: `Number`
33 | * required: `false`
34 | * default: `12`
35 |
36 | Says how many columns the grid has.
37 |
38 | The value should be a _natural number_.
39 |
40 | ### rowHeight
41 |
42 | * type: `Number`
43 | * required: `false`
44 | * default: `150`
45 |
46 | Says what is a height of a single row in pixels.
47 |
48 | ### maxRows
49 |
50 | * type: `Number`
51 | * required: `false`
52 | * default: `Infinity`
53 |
54 | Says what is a maximal number of rows in the grid.
55 |
56 | ### margin
57 |
58 | * type: `Array`
59 | * required: `false`
60 | * default: `[10, 10]`
61 |
62 | Says what are the margins of elements inside the grid.
63 |
64 | The value must be a two-element `Array` of `Number`. Each value is expressed in pixels. The first element is a margin horizontally, the second element is a vertical margin.
65 |
66 | ### isDraggable
67 |
68 | * type: `Boolean`
69 | * required: `false`
70 | * default: `true`
71 |
72 | Says if the grids items are draggable.
73 |
74 | ### isResizable
75 |
76 | * type: `Boolean`
77 | * required: `false`
78 | * default: `true`
79 |
80 | Says if the grids items are resizable.
81 |
82 | ### isMirrored
83 |
84 | * type: `Boolean`
85 | * required: `false`
86 | * default: `false`
87 |
88 | Says if the RTL/LTR should be reversed.
89 |
90 | ### isBounded
91 |
92 | * type: `Boolean`
93 | * required: `false`
94 | * default: `false`
95 |
96 | Says if the grid items are bounded to the container when dragging
97 |
98 | ### autoSize
99 |
100 | * type: `Boolean`
101 | * required: `false`
102 | * default: `true`
103 |
104 | Says if the container height should swells and contracts to fit contents.
105 |
106 | ### verticalCompact
107 |
108 | * type: `Boolean`
109 | * required: `false`
110 | * default: `true`
111 |
112 | Says if the layout should be compact vertically.
113 |
114 | ### restoreOnDrag
115 |
116 | * type: `Boolean`
117 | * required: `false`
118 | * default: `false`
119 |
120 | Says if the moved grid items should be restored after an item has been dragged over.
121 |
122 | ### preventCollision
123 |
124 | * type: `Boolean`
125 | * required: `false`
126 | * default: `false`
127 |
128 | Says if grid items will move when being dragged over.
129 |
130 | ### useCssTransforms
131 |
132 | * type: `Boolean`
133 | * required: `false`
134 | * default: `true`
135 |
136 | Says if the CSS `transition-property: transform;` should be used.
137 |
138 | ### responsive
139 |
140 | * type: `Boolean`
141 | * required: `false`
142 | * default: `false`
143 |
144 | Says if the layout should be responsive to window width
145 |
146 | See also [responsiveLayouts](#responsivelayouts), [breakpoints](#breakpoints) and [cols](#cols)
147 |
148 |
149 | ### breakpoints
150 |
151 | * type: `Object`
152 | * required: `false`
153 | * default: `{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }`
154 |
155 | Breakpoints defined for responsive layout, the parameter represents the width of different devices:lg(large), md(medium), sm(small), xs(extra small). Sets widths on wich column number changes
156 |
157 | See also [responsiveLayouts](#responsivelayouts) and [cols](#cols)
158 |
159 | ### cols
160 |
161 | * type: `Object`
162 | * required: `false`
163 | * default: `{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }`
164 |
165 | Defines number of columns for each breakpoint
166 |
167 | ### useStyleCursor
168 |
169 | * type: `Boolean`
170 | * required: `false`
171 | * default: `true`
172 |
173 | Says if set the `styleCursor` option to true. When dragging freezes, setting this value to `false` may alleviate problems.
174 | **This property is not reactive**
175 |
176 |
177 | ### transformScale
178 |
179 | * type: `Number`
180 | * required: `false`
181 | * default: 1
182 |
183 | Sets a scaling factor to the size of the grid items, 1 is 100%
184 |
185 | ## GridItem
186 |
187 | ### i
188 |
189 | * type: `String`
190 | * required: `true`
191 |
192 | This is the unique identifier of the item.
193 |
194 | ### x
195 |
196 | * type: `Number`
197 | * required: `true`
198 |
199 | Says what is a initial horizontal position of the item (in which column it should be placed).
200 |
201 | The value must be a _whole number_.
202 |
203 | ### y
204 |
205 | * type: `Number`
206 | * required: `true`
207 |
208 | Says what is a initial vertical position of the item (in which row it should be placed).
209 |
210 | The value must be a _whole number_.
211 |
212 | ### w
213 |
214 | * type: `Number`
215 | * required: `true`
216 |
217 | Says what is a initial width of the item.
218 |
219 | The value is a number that is multiplied by `colWidth`.
220 |
221 | ### h
222 |
223 | * type: `Number`
224 | * required: `true`
225 |
226 | Says what is a initial height of the item.
227 |
228 | The value is a number that is multiplied by `rowHeight`.
229 |
230 | ### minW
231 |
232 | * type: `Number`
233 | * required: `false`
234 | * default: `1`
235 |
236 | Says what is a minimal width of the item. If `w` will be smaller then `minW` then `w` will be set to `minW`.
237 |
238 | The value is a number that is multiplied by `colWidth`.
239 |
240 | ### minH
241 |
242 | * type: `Number`
243 | * required: `false`
244 | * default: `1`
245 |
246 | Says what is a minimal hieght of the item. If `h` will be smaller then `minH` then `h` will be set to `minH`.
247 |
248 | The value is a number that is multiplied by `rowHeight`.
249 |
250 | ### maxW
251 |
252 | * type: `Number`
253 | * required: `false`
254 | * default: `Infinity`
255 |
256 | Says what is a maximal width of the item. If `w` will be bigger then `maxW` then `w` will be set to `maxW`.
257 |
258 | The value is a number that is multiplied by `colWidth`.
259 |
260 | ### maxH
261 |
262 | * type: `Number`
263 | * required: `false`
264 | * default: `Infinity`
265 |
266 | Says what is a maximal height of the item. If `h` will be bigger then `maxH` then `h` will be set to `maxH`.
267 |
268 | The value is a number that is multiplied by `rowHeight`
269 |
270 | ### isDraggable
271 |
272 | * type: `Boolean`
273 | * required: `false`
274 | * default: `null`
275 |
276 | Says if item is draggable.
277 |
278 | If default value is `null` then it's inherited from parent.
279 |
280 | ### isResizable
281 |
282 | * type: `Boolean`
283 | * required: `false`
284 | * default: `null`
285 |
286 | Says if item is resizable.
287 |
288 | If default value is `null` then it's inherited from parent.
289 |
290 | ### isBounded
291 |
292 | * type: `Boolean`
293 | * required: `false`
294 | * default: `null`
295 |
296 | Says if the item is bounded to the container when dragging.
297 |
298 | If default value is `null` then it's inherited from parent.
299 |
300 | ### static
301 |
302 | * type: `Boolean`
303 | * required: `false`
304 | * default: `false`
305 |
306 | Says if item is static (won't be draggable, resizable or moved by other items).
307 |
308 |
309 | ### dragIgnoreFrom
310 |
311 | * type: `String`
312 | * required: `false`
313 | * default: `'a, button'`
314 |
315 | Says which elements of the item shouldn't trigger drag event of the item.
316 |
317 | The value is `css-like` selector string.
318 |
319 | For more info please refer to `ignoreFrom` in [interact.js docs](http://interactjs.io/docs/#ignorable-selectors).
320 |
321 | ### dragAllowFrom
322 |
323 | * type: `String`
324 | * required: `false`
325 | * default: `null`
326 |
327 | Says which elements of the item should trigger drag event of the item.
328 |
329 | The value is `css-like` selector string.
330 |
331 | If `null` then one can drag by any (excluding `dragIgnoreFrom`) element of the item.
332 |
333 | For more info please refer to `allowFrom` in [interact.js docs](http://interactjs.io/docs/#ignorable-selectors).
334 |
335 | ### resizeIgnoreFrom
336 |
337 | * type: `String`
338 | * required: `false`
339 | * default: `'a, button'`
340 |
341 | Says which elements of the item shouldn't trigger resize event of the item.
342 |
343 | The value is `css-like` selector string.
344 |
345 | For more info please refer to `ignoreFrom` in [interact.js docs](http://interactjs.io/docs/#ignorable-selectors).
346 |
347 |
348 | ### preserveAspectRatio
349 |
350 | * type: `Boolean`
351 | * required: `false`
352 | * default: `false`
353 |
354 | If 'true', forces the GridItem to preserve its aspect ratio when resizing.
355 |
356 |
357 | ### dragOption
358 |
359 | * type: `Object`
360 | * required: `false`
361 | * default: `{}`
362 |
363 | Passthrough object for the grid item [interact.js draggable configuration](https://interactjs.io/docs/draggable/)
364 |
365 | ### resizeOption
366 |
367 | * type: `Object`
368 | * required: `false`
369 | * default: `{}`
370 |
371 | Passthrough object for the grid item [interact.js resizable configuration](https://interactjs.io/docs/resizable/)
372 |
373 |
--------------------------------------------------------------------------------
/website/src/guide/readme.md:
--------------------------------------------------------------------------------
1 | index.md
--------------------------------------------------------------------------------
/website/src/guide/styling.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: true
3 | ---
4 |
8 |
9 | # Styling
10 |
11 | Grid styling can be customized to fit your needs. Below is a list of the classes you can override.
12 |
13 | ## Placeholder
14 |
15 | The default css for the placeholder is:
16 |
17 | ````css
18 | .vue-grid-item.vue-grid-placeholder {
19 | background: red;
20 | opacity: 0.2;
21 | transition-duration: 100ms;
22 | z-index: 2;
23 | -webkit-user-select: none;
24 | -moz-user-select: none;
25 | -ms-user-select: none;
26 | -o-user-select: none;
27 | user-select: none;
28 | }
29 | ````
30 |
31 | You can override the properties using the !important rule:
32 |
33 | ````css
34 | .vue-grid-item.vue-grid-placeholder {
35 | background: green !important;
36 | }
37 | ````
38 |
39 | Or by wrapping your grid with a more [specific](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) class:
40 |
41 | ````css
42 | .container .vue-grid-item.vue-grid-placeholder {
43 | background: green;
44 | }
45 | ````
46 |
47 | in scoped
48 |
49 | ````css
50 | :deep(.vue-grid-item.vue-grid-placeholder) {
51 | background: green;
52 | }
53 | ````
54 |
55 |
56 | In this example we change the placeholder background color to green:
57 |
58 |
59 |
60 |
61 |
62 | <<< @/example/styling-placeholder.vue
63 |
64 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/styling-placeholder.vue)
65 |
66 |
67 | ## Grid lines
68 |
69 | To add grid lines to the layout, add the ``grid`` class to the grid-layout element and use the css:
70 |
71 | ````css
72 | .grid::before {
73 | content: '';
74 | background-size: calc(calc(100% - 5px) / 12) 40px;
75 | background-image: linear-gradient(
76 | to right,
77 | lightgrey 1px,
78 | transparent 1px
79 | ),
80 | linear-gradient(to bottom, lightgrey 1px, transparent 1px);
81 | height: calc(100% - 5px);
82 | width: calc(100% - 5px);
83 | position: absolute;
84 | background-repeat: repeat;
85 | margin:5px;
86 | }
87 | ````
88 |
89 | CSS calculations for grid lines:
90 |
91 | * background size = calc(calc(100% - (margin/2)) / colNum) rowHeight + margin;
92 | * height: calc(100% - (margin/2))
93 | * width: calc(100% - (margin/2))
94 | * margin: margin / 2
95 |
96 |
97 |
98 |
99 |
100 | <<< @/example/styling-grid-lines.vue
101 |
102 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/styling-grid-lines.vue)
103 |
104 |
105 |
--------------------------------------------------------------------------------
/website/src/guide/usage.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # Usage
6 | [View source](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/src/example/usage.vue)
7 |
8 | <<< @/example/usage.vue
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/website/src/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | # https://vitepress.dev/reference/default-theme-home-page
3 | layout: home
4 |
5 | hero:
6 | name: "Vue3 Grid Layout"
7 | text: "A draggable and resizable grid layout, as a Vue component."
8 | image: /logo.png
9 | tagline: A grid layout system for Vue.js, like
10 | Gridster,
11 | for Vue.js. Heavily inspired by
12 | React-Grid-Layout
13 | actions:
14 | - theme: brand
15 | text: Get Started →
16 | link: /guide
17 |
18 | features:
19 | - title: Draggable
20 | - title: Resizable
21 | - title: Responsive
22 | ---
23 |
24 |
--------------------------------------------------------------------------------
/website/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import App from './app.vue';
3 |
4 | createApp(App).mount('#app');
5 |
6 |
--------------------------------------------------------------------------------
/website/src/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merfais/vue-grid-layout-v3/a669942fa85c80211767b89acddbe6211319ffe2/website/src/public/favicon.ico
--------------------------------------------------------------------------------
/website/src/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merfais/vue-grid-layout-v3/a669942fa85c80211767b89acddbe6211319ffe2/website/src/public/logo.png
--------------------------------------------------------------------------------
/website/src/readme.md:
--------------------------------------------------------------------------------
1 | index.md
--------------------------------------------------------------------------------
/website/src/zh/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: HomeLayout
3 | home: true
4 | heroImage: /assets/img/logo.png
5 | heroText: Vue Grid Layout
6 | tagline: 一个类似于Gridster的栅格布局系统, 适用于Vue.js。灵感源自于React-Grid-Layout
7 | actionText: 开始 →
8 | actionLink: /zh/guide/
9 | features:
10 | - title: ✥ 可拖拽
11 | details:
12 | - title: ⇲ 可调整大小
13 | details:
14 | - title: 静态部件(不可拖拽、调整大小)
15 | details:
16 | - title: 拖拽和调整大小时进行边界检查
17 | details:
18 | - title: 增减部件时避免重建栅格
19 | details:
20 | - title: 可序列化和还原的布局
21 | details:
22 | - title: 自动化 RTL 支持
23 | details:
24 | - title: 响应式
25 | details:
26 | - title: Min/max w/h per item
27 | details:
28 | ---
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/website/src/zh/guide/01-basic.md:
--------------------------------------------------------------------------------
1 | # 01 - 基本
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example01Basic.vue)
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/website/src/zh/guide/02-events.md:
--------------------------------------------------------------------------------
1 | # 02 - 移动事件并调整大小
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example02Events.vue)
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/website/src/zh/guide/03-multiple-grids.md:
--------------------------------------------------------------------------------
1 | # 03 - 多个栅格
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example03MultipleGrids.vue)
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/website/src/zh/guide/04-allow-ignore.md:
--------------------------------------------------------------------------------
1 | # 04 - 拖动允许/忽略元素
2 |
3 | 忽略对某些元素的拖动而对其他元素的允许。
4 |
5 | 单击并拖动每个项目角上的点以重新定位
6 |
7 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example04AllowIgnore.vue)
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/website/src/zh/guide/05-mirrored.md:
--------------------------------------------------------------------------------
1 | # 05 - 镜像反转栅格布局
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example05Mirrored.vue)
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/website/src/zh/guide/06-responsive.md:
--------------------------------------------------------------------------------
1 | # 06 - 响应式
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example06Responsive.vue)
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/website/src/zh/guide/07-prevent-collision.md:
--------------------------------------------------------------------------------
1 | # 07 - 防止碰撞
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example07PreventCollision.vue)
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/website/src/zh/guide/08-responsive-predefined-layouts.md:
--------------------------------------------------------------------------------
1 | # 08 - 响应预定义的布局
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example08ResponsivePredefinedLayouts.vue)
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/website/src/zh/guide/09-dynamic-add-remove.md:
--------------------------------------------------------------------------------
1 | # 09 - 动态添加/删除
2 |
3 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example09DynamicAddRemove.vue)
4 |
5 |
6 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/website/src/zh/guide/10-drag-from-outside.md:
--------------------------------------------------------------------------------
1 | # 10 - 从外面拖动
2 |
3 | 该演示演示了从栅格外部添加部件时发生的情况。
4 |
5 | 将部件放到栅格中后,您将获得其坐标/属性,并可以据此执行操作。
6 |
7 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example10DragFromOutside.vue)
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/website/src/zh/guide/11-bounded.md:
--------------------------------------------------------------------------------
1 | # 11 - 拖动栅格元素绑定到容器
2 |
3 | 可以获得栅格元素的坐标与容器间的绑定关系。
4 |
5 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/Example11Bounded.vue)
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/website/src/zh/guide/README.md:
--------------------------------------------------------------------------------
1 | # 安装
2 |
3 | ## NPM
4 |
5 | npm install vue-grid-layout-v3 --save
6 |
7 | ## Yarn
8 |
9 | yarn add vue-grid-layout-v3
10 |
11 |
12 | 导入库
13 |
14 | ```javascript
15 | import VueGridLayout from 'vue-grid-layout-v3';
16 | ```
17 |
18 | 添加到其他Vue组件
19 |
20 | ```javascript
21 | export default {
22 | components: {
23 | GridLayout: VueGridLayout.GridLayout,
24 | GridItem: VueGridLayout.GridItem
25 | },
26 | // ... data, methods, mounted (), etc.
27 | }
28 |
29 | ```
30 |
31 | ## 浏览器
32 |
33 | 包括可用于浏览器的软件包([从发布版本](https://github.com/merfais/vue-grid-layout-v3/releases)下载)。组件将自动可用。
34 |
35 | ```html
36 |
37 | ```
38 |
39 |
--------------------------------------------------------------------------------
/website/src/zh/guide/auto-size.md:
--------------------------------------------------------------------------------
1 | # 自动调整栅格元素
2 |
3 | 待办: https://github.com/merfais/vue-grid-layout-v3/issues/351
4 |
--------------------------------------------------------------------------------
/website/src/zh/guide/events.md:
--------------------------------------------------------------------------------
1 | # 事件
2 |
3 | 每一个栅格元素grid-item上都可以添加监听器,用于监听移动和调整大小事件,这样父级Vue对象就可以收到通知。
4 |
5 | 示例 [点击这里](../guide/02-events.md)
6 |
7 | ````html
8 |
9 |
25 |
26 |
38 | {{item.i}}
39 |
40 |
41 | ````
42 |
43 | ## GridLayout
44 |
45 | ### layoutCreatedEvent
46 |
47 | 对应Vue生命周期的created
48 |
49 | ```javascript
50 | layoutCreatedEvent: function(newLayout){
51 | console.log("Created layout: ", newLayout)
52 | }
53 | ```
54 |
55 | ### layoutBeforeMountEvent
56 |
57 | 对应Vue生命周期的beforeMount
58 |
59 | ```javascript
60 | layoutBeforeMountEvent: function(newLayout){
61 | console.log("beforeMount layout: ", newLayout)
62 | }
63 | ```
64 |
65 | ### layoutMountedEvent
66 |
67 | 对应Vue生命周期的mounted
68 |
69 | ```javascript
70 | layoutMountedEvent: function(newLayout){
71 | console.log("Mounted layout: ", newLayout)
72 | }
73 | ```
74 |
75 | ### layoutReadyEvent
76 |
77 | 当完成mount中的所有操作时生成的事件
78 |
79 | ```javascript
80 | layoutReadyEvent: function(newLayout){
81 | console.log("Ready layout: ", newLayout)
82 | }
83 | ```
84 |
85 | ### layoutUpdatedEvent
86 |
87 | 布局updated事件
88 |
89 | 更新事件(布局更新或栅格元素的位置重新计算)
90 |
91 | ```javascript
92 | layoutUpdatedEvent: function(newLayout){
93 | console.log("Updated layout: ", newLayout)
94 | }
95 | ```
96 |
97 |
98 | ### breakpointChangedEvent
99 |
100 | 断点更改事件
101 |
102 | 每次断点值由于窗口调整大小而改变
103 |
104 | ```javascript
105 | /**
106 | *
107 | * @param newBreakpoint the breakpoint name
108 | * @param newLayout the chosen layout for the breakpoint
109 | *
110 | */
111 | breakpointChangedEvent: function(newBreakpoint, newLayout){
112 | console.log("BREAKPOINT CHANGED breakpoint=", newBreakpoint, ", layout: ", newLayout );
113 | },
114 | ```
115 |
116 |
117 | ## GridItem
118 |
119 | ### moveEvent
120 |
121 | 移动时的事件
122 |
123 | ```javascript
124 | moveEvent: function(i, newX, newY){
125 | console.log("MOVE i=" + i + ", X=" + newX + ", Y=" + newY);
126 | },
127 | ```
128 |
129 | ### resizeEvent
130 |
131 | 调整大小时的事件
132 |
133 | ```javascript
134 | resizeEvent: function(i, newH, newW, newHPx, newWPx){
135 | console.log("RESIZE i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
136 | },
137 | ```
138 |
139 | ### movedEvent
140 |
141 | 移动后的事件
142 |
143 | ```javascript
144 | movedEvent: function(i, newX, newY){
145 | console.log("MOVED i=" + i + ", X=" + newX + ", Y=" + newY);
146 | },
147 | ```
148 |
149 | ### resizedEvent
150 |
151 | 调整大小后的事件
152 |
153 | ```javascript
154 | /**
155 | *
156 | * @param i the item id/index
157 | * @param newH new height in grid rows
158 | * @param newW new width in grid columns
159 | * @param newHPx new height in pixels
160 | * @param newWPx new width in pixels
161 | *
162 | */
163 | resizedEvent: function(i, newH, newW, newHPx, newWPx){
164 | console.log("RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
165 | },
166 | ```
167 |
168 | ### containerResizedEvent
169 |
170 | 栅格元素/栅格容器更改大小的事件(浏览器窗口或其他)
171 |
172 |
173 | ```javascript
174 | /**
175 | *
176 | * @param i the item id/index
177 | * @param newH new height in grid rows
178 | * @param newW new width in grid columns
179 | * @param newHPx new height in pixels
180 | * @param newWPx new width in pixels
181 | *
182 | */
183 | containerResizedEvent: function(i, newH, newW, newHPx, newWPx){
184 | console.log("CONTAINER RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
185 | },
186 | ```
187 |
188 |
--------------------------------------------------------------------------------
/website/src/zh/guide/examples.md:
--------------------------------------------------------------------------------
1 | # 例子
2 |
3 | ## 基本
4 |
5 |
6 |
7 | ## 事件
8 |
9 |
10 |
11 | ## 多个网格
12 |
13 |
14 |
15 | ## 拖动允许/忽略元素
16 |
17 | 忽略对某些元素的拖动,而对其他元素允许。
18 |
19 | 单击并拖动每个栅格角上的点以重新定位
20 |
21 |
22 |
--------------------------------------------------------------------------------
/website/src/zh/guide/properties.md:
--------------------------------------------------------------------------------
1 | # 属性
2 |
3 | ## GridLayout
4 |
5 | ### layout
6 |
7 |
8 | * type: `Array`
9 | * required: `true`
10 |
11 | 这是栅格的初始布局。
12 |
13 | 数据源。值必须为 `Array`,其数据项为 `Object`。 每条数据项必须有 `i, x, y, w 和 h` 属性。 请参考下面的 `GridItem`。
14 |
15 | ### responsiveLayouts
16 |
17 | * type: `Object`
18 | * required: `false`
19 | * default : `{}`
20 |
21 | 如果 `responsive` 设置为 `true`,该配置将作为栅格中每个断点的初始布局。键值是断点名称,每项的值都是类似 `layout` 属性定义的数据结构,值必须为 `Array`,其数据项为 `Object`。例如: `{lg: [layout items], md: [layout items]}`。需要注意的是,在创建栅格布局后设置该属性无效。
22 | 在创建GridLayout之后设置prop无效。
23 |
24 | 可以查看 [responsive](#responsive), [breakpoints](#breakpoints) 和 [cols](#cols)
25 |
26 | ### colNum
27 |
28 | * type: `Number`
29 | * required: `false`
30 | * default: `12`
31 |
32 | 定义栅格系统的列数,其值需为自然数。
33 |
34 | ### rowHeight
35 |
36 | * type: `Number`
37 | * required: `false`
38 | * default: `150`
39 |
40 | 每行的高度,单位像素。
41 |
42 | ### maxRows
43 |
44 | * type: `Number`
45 | * required: `false`
46 | * default: `Infinity`
47 |
48 | 定义最大行数。
49 |
50 | ### margin
51 |
52 | * type: `Array`
53 | * required: `false`
54 | * default: `[10, 10]`
55 |
56 | 定义栅格中的元素边距。
57 |
58 | 值必须是包含两个 `Number`的数组,数组中第一个元素表示水平边距,第二个表示垂直边距,单位为像素。
59 |
60 | ### isDraggable
61 |
62 | * type: `Boolean`
63 | * required: `false`
64 | * default: `true`
65 |
66 | 标识栅格中的元素是否可拖拽。
67 |
68 | ### isResizable
69 |
70 | * type: `Boolean`
71 | * required: `false`
72 | * default: `true`
73 |
74 | 标识栅格中的元素是否可调整大小。
75 |
76 | ### isMirrored
77 |
78 | * type: `Boolean`
79 | * required: `false`
80 | * default: `false`
81 |
82 | 标识栅格中的元素是否可镜像反转。
83 |
84 | ### autoSize
85 |
86 | * type: `Boolean`
87 | * required: `false`
88 | * default: `true`
89 |
90 | 标识容器是否自动调整大小。
91 |
92 | ### verticalCompact
93 |
94 | * type: `Boolean`
95 | * required: `false`
96 | * default: `true`
97 |
98 | 标识布局是否垂直压缩。
99 |
100 | ### preventCollision
101 |
102 | * type: `Boolean`
103 | * required: `false`
104 | * default: `false`
105 |
106 | 防止碰撞属性,值设置为`ture`时,栅格只能拖动至空白处。
107 |
108 | ### useCssTransforms
109 |
110 | * type: `Boolean`
111 | * required: `false`
112 | * default: `true`
113 |
114 | 标识是否使用CSS属性 `transition-property: transform;`。
115 |
116 | ### responsive
117 |
118 | * type: `Boolean`
119 | * required: `false`
120 | * default: `false`
121 |
122 | 标识布局是否为响应式。
123 |
124 | 可以查看 [responsiveLayouts](#responsivelayouts)、[breakpoints](#breakpoints)和 [cols](#cols)
125 |
126 |
127 | ### breakpoints
128 |
129 | * type: `Object`
130 | * required: `false`
131 | * default: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }
132 |
133 | 为响应式布局设置断点。
134 |
135 | 可以查看 [responsiveLayouts](#responsivelayouts) 和 [cols](#cols)
136 |
137 | ### cols
138 |
139 | * type: `Object`
140 | * required: `false`
141 | * default: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }
142 |
143 | 设置每个断点对应的列数。
144 |
145 | ### useStyleCursor
146 |
147 | * type: `Boolean`
148 | * required: `false`
149 | * default: `true`
150 |
151 | 标识是否使用动态鼠标指针样式。当拖动出现卡顿时,将此值设为 `false`也许可以缓解布局问题。
152 | **此属性无效**
153 |
154 | ## GridItem
155 |
156 | ### i
157 |
158 | * type: `String`
159 | * required: `true`
160 |
161 | 栅格中元素的ID。
162 |
163 | ### x
164 |
165 | * type: `Number`
166 | * required: `true`
167 |
168 | 标识栅格元素位于第几列,需为自然数。
169 |
170 | ### y
171 |
172 | * type: `Number`
173 | * required: `true`
174 |
175 | 标识栅格元素位于第几行,需为自然数。
176 |
177 | ### w
178 |
179 | * type: `Number`
180 | * required: `true`
181 |
182 | 标识栅格元素的初始宽度,值为`colWidth`的倍数。
183 |
184 | ### h
185 |
186 | * type: `Number`
187 | * required: `true`
188 |
189 | 标识栅格元素的初始高度,值为`rowHeight`的倍数。
190 |
191 | ### minW
192 |
193 | * type: `Number`
194 | * required: `false`
195 | * default: `1`
196 |
197 | 栅格元素的最小宽度,值为`colWidth`的倍数。
198 |
199 | 如果`w`小于`minW`,则`minW`的值会被`w`覆盖。
200 |
201 | ### minH
202 |
203 | * type: `Number`
204 | * required: `false`
205 | * default: `1`
206 |
207 | 栅格元素的最小高度,值为`rowHeight`的倍数。
208 |
209 | 如果`h`小于`minH`,则`minH`的值会被h覆盖。
210 |
211 | ### maxW
212 |
213 | * type: `Number`
214 | * required: `false`
215 | * default: `Infinity`
216 |
217 | 栅格元素的最大宽度,值为`colWidth`的倍数。
218 |
219 | 如果`w`大于`maxW`,则`maxW`的值会被`w`覆盖。
220 |
221 | ### maxH
222 |
223 | * type: `Number`
224 | * required: `false`
225 | * default: `Infinity`
226 |
227 | 栅格元素的最大高度,值为`rowHeight`的倍数。
228 |
229 | 如果`h`大于`maxH`,则`maxH`的值会被`h`覆盖。
230 |
231 | ### isDraggable
232 |
233 | * type: `Boolean`
234 | * required: `false`
235 | * default: `null`
236 |
237 | 标识栅格元素是否可拖拽。如果值为`null`则取决于父容器。
238 |
239 | ### isResizable
240 |
241 | * type: `Boolean`
242 | * required: `false`
243 | * default: `null`
244 |
245 | 标识栅格元素是否可调整大小。如果值为`null`则取决于父容器。
246 |
247 | ### static
248 |
249 | * type: `Boolean`
250 | * required: `false`
251 | * default: `false`
252 |
253 | 标识栅格元素是否为静态的(无法拖拽、调整大小或被其他元素移动)。
254 |
255 | ### dragIgnoreFrom
256 |
257 | * type: `String`
258 | * required: `false`
259 | * default: `'a, button'`
260 |
261 | 标识栅格元素中哪些子元素无法触发拖拽事件,值为`css-like`选择器。
262 |
263 | 请参考[interact.js docs](http://interactjs.io/docs/#ignorable-selectors)中的`ignoreFrom`。
264 |
265 | ### dragAllowFrom
266 |
267 | * type: `String`
268 | * required: `false`
269 | * default: `null`
270 |
271 | 标识栅格元素中哪些子元素可以触发拖拽事件,值为`css-like`选择器。
272 |
273 | 如果值为`null`则表示所有子元素(`dragIgnoreFrom`的除外)。
274 |
275 | 请参考[interact.js docs](http://interactjs.io/docs/#ignorable-selectors)中的`allowFrom`。
276 |
277 | ### resizeIgnoreFrom
278 |
279 | * type: `String`
280 | * required: `false`
281 | * default: `'a, button'`
282 |
283 | 标识栅格元素中哪些子元素无法触发调整大小的事件,值为`css-like`选择器。
284 |
285 | 请参考[interact.js docs](http://interactjs.io/docs/#ignorable-selectors)中的`ignoreFrom`。
286 |
--------------------------------------------------------------------------------
/website/src/zh/guide/styling.md:
--------------------------------------------------------------------------------
1 | # 样式
2 |
3 | 可以定制栅格样式以适合您的需求。以下是可以覆盖的类的列表。
4 |
5 | ## 占位符
6 |
7 | 占位符的默认css为:
8 |
9 | ````css
10 | .vue-grid-item.vue-grid-placeholder {
11 | background: red;
12 | opacity: 0.2;
13 | transition-duration: 100ms;
14 | z-index: 2;
15 | -webkit-user-select: none;
16 | -moz-user-select: none;
17 | -ms-user-select: none;
18 | -o-user-select: none;
19 | user-select: none;
20 | }
21 | ````
22 |
23 | 您可以使用`!important`规则覆盖属性:
24 |
25 | ````css
26 | .vue-grid-item.vue-grid-placeholder {
27 | background: green !important;
28 | }
29 | ````
30 |
31 | 或者通过用更[具体的](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity)方式包装栅格类:
32 |
33 | ````css
34 | .container .vue-grid-item.vue-grid-placeholder {
35 | background: green;
36 | }
37 | ````
38 |
39 | 在此示例中,我们将占位符的背景色更改为绿色:
40 |
41 | [查看资料](https://github.com/merfais/vue-grid-layout-v3/blob/master/website/docs/.vuepress/components/ExampleStylingPlaceholder.vue)
42 |
43 |
44 |
45 |
46 |
47 |
48 | 工作正在进行中...
49 |
--------------------------------------------------------------------------------
/website/src/zh/guide/usage.md:
--------------------------------------------------------------------------------
1 | # 用法
2 |
3 | ```javascript
4 | new Vue({
5 | el: '#app',
6 | data: {
7 | layout: [
8 | {"x":0,"y":0,"w":2,"h":2,"i":"0"},
9 | {"x":2,"y":0,"w":2,"h":4,"i":"1"},
10 | {"x":4,"y":0,"w":2,"h":5,"i":"2"},
11 | {"x":6,"y":0,"w":2,"h":3,"i":"3"},
12 | {"x":8,"y":0,"w":2,"h":3,"i":"4"},
13 | {"x":10,"y":0,"w":2,"h":3,"i":"5"},
14 | {"x":0,"y":5,"w":2,"h":5,"i":"6"},
15 | {"x":2,"y":5,"w":2,"h":5,"i":"7"},
16 | {"x":4,"y":5,"w":2,"h":5,"i":"8"},
17 | {"x":6,"y":3,"w":2,"h":4,"i":"9"},
18 | {"x":8,"y":4,"w":2,"h":4,"i":"10"},
19 | {"x":10,"y":4,"w":2,"h":4,"i":"11"},
20 | {"x":0,"y":10,"w":2,"h":5,"i":"12"},
21 | {"x":2,"y":10,"w":2,"h":5,"i":"13"},
22 | {"x":4,"y":8,"w":2,"h":4,"i":"14"},
23 | {"x":6,"y":8,"w":2,"h":4,"i":"15"},
24 | {"x":8,"y":10,"w":2,"h":5,"i":"16"},
25 | {"x":10,"y":4,"w":2,"h":2,"i":"17"},
26 | {"x":0,"y":9,"w":2,"h":3,"i":"18"},
27 | {"x":2,"y":6,"w":2,"h":2,"i":"19"}
28 | ],
29 | },
30 | });
31 | ```
32 |
33 |
34 | ```html
35 |
36 |
47 |
48 |
55 | {{item.i}}
56 |
57 |
58 | ```
59 |
--------------------------------------------------------------------------------
/website/vite.config.js:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'node:url';
2 | import { defineConfig } from 'vite';
3 | import vue from '@vitejs/plugin-vue';
4 | import eslint from '@rollup/plugin-eslint';
5 |
6 | // https://vitejs.dev/config/
7 | export default defineConfig(() => ({
8 | plugins: [
9 | vue(),
10 | eslint({
11 | include: ['**/*.js', '**/*.vue'],
12 | }),
13 | ],
14 | resolve: {
15 | alias: {
16 | '@': fileURLToPath(new URL('./src', import.meta.url)),
17 | },
18 | },
19 | }));
20 |
--------------------------------------------------------------------------------