+ +
Grid #1
+Grid #2
++ +
+
[x, y, w, h]:
+ + Draggable + Resizable + Responsive +
+
[x, y, w, h]:
+ [x, y, w, h]:
+ +
[x, y, w, h]:
+ + Draggable + Resizable + Bounded +
+
+ diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..c2925fb8
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: jbaysolutions
diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
new file mode 100644
index 00000000..a6d9d440
--- /dev/null
+++ b/.github/workflows/build-test.yml
@@ -0,0 +1,32 @@
+name: Build and Test
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [10.x, 12.x, 14.x, 15.x]
+ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+ - name: Install dependency
+ run: yarn
+ - name: Lint check
+ run: yarn lint
+ - name: Build
+ run: yarn build
+ - name: Unit test
+ run: yarn test:unit
diff --git a/.github/workflows/vuepress-deploy.yml b/.github/workflows/vuepress-deploy.yml
new file mode 100644
index 00000000..a936b2b7
--- /dev/null
+++ b/.github/workflows/vuepress-deploy.yml
@@ -0,0 +1,24 @@
+name: Deploy vuepress website
+on:
+ push:
+ branches:
+ - master
+jobs:
+ build-and-deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@master
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '16'
+
+ - name: vuepress-deploy
+ uses: jenkey2011/vuepress-deploy@master
+ env:
+ ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
+ TARGET_REPO: jbaysolutions/vue-grid-layout
+ TARGET_BRANCH: gh-pages
+ BUILD_SCRIPT: cd website && yarn && yarn build
+ BUILD_DIR: public
diff --git a/.gitignore b/.gitignore
index 76571c9f..83dfe282 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,5 +21,6 @@ yarn-error.log*
*.sln
*.sw*
-yarn.lock
-yarn-error.log
\ No newline at end of file
+yarn-error.log
+
+website/docs/dist
diff --git a/README-zh_CN.md b/README-zh_CN.md
index 65074738..e940b464 100644
--- a/README-zh_CN.md
+++ b/README-zh_CN.md
@@ -6,10 +6,10 @@
vue-grid-layout是一个类似于[Gridster](http://dsmorse.github.io/gridster.js/)的栅格布局系统, 适用于Vue.js。 **灵感源自于 [React-Grid-Layout](https://github.com/STRML/react-grid-layout)**
-### **当前版本:** 2.3.7 (支持 Vue 2.2+)
+### **当前版本:** 2.4.0 (支持 Vue 2.2+)
### **Vue 2.1.10 及以下请使用 [2.1.3](https://github.com/jbaysolutions/vue-grid-layout/tree/2.1.3)**
-### **Vue 1 请使用 [1.0.3](https://github.com/jbaysolutions/vue-grid-layout/tree/1.0.3)**
+### **Vue 1 请使用 [1.0.3](https://github.com/jbaysolutions/vue-grid-layout/tree/1.0.3)**
@@ -39,8 +39,8 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
#### 成功案例
+- [DocsFold](https://www.docsfold.com/?utm_source=github&utm_medium=web&utm_campaign=vue-grid-layout)
- [Draxed](https://www.draxed.com/?utm_source=github&utm_medium=web&utm_campaign=vue-grid-layout)
-- [cryptotiles](https://www.cryptotiles.io/?utm_source=github&utm_medium=web&utm_campaign=vue-grid-layout)
- [Data Providers](https://www.dataproviders.io/?utm_source=github&utm_medium=web&utm_campaign=vue-grid-layout)
- [Cataholic](https://cataholic.glitch.me/)
@@ -64,10 +64,10 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
#### npm
- # 使用 npm
+ # 使用 npm
npm install vue-grid-layout --save
-
- # 使用 yarn
+
+ # 使用 yarn
yarn add vue-grid-layout
@@ -77,7 +77,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
import VueGridLayout from 'vue-grid-layout';
```
-加入到 Vue 组件
+加入到 Vue 组件
```javascript
export default {
@@ -87,8 +87,8 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
},
// ... data, methods, mounted (), etc.
}
-
-```
+
+```
#### 浏览器
@@ -123,14 +123,14 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
{"x":0,"y":9,"w":2,"h":3,"i":"18"},
{"x":2,"y":6,"w":2,"h":2,"i":"19"}
];
-
+
new Vue({
el: '#app',
data: {
layout: testLayout,
},
});
-```
+```
```html
@@ -167,14 +167,22 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
##### GridLayout
* **layout**
-
+
* type: `Array`
* required: `true`
数据源。值必须为 `Array`,其数据项为 `Object`。 每条数据项必须有 `i`, `x`, `y`, `w` 和 `h` 属性。 请参考下面的 `GridItem`。
+* **responsiveLayouts**
+
+ * type: `Object`
+ * required: `false`
+ * default: `{}`
+
+ 如果 `responsive` 设置为 `true`,该配置将作为栅格中每个断点的初始布局。键值是断点名称,每项的值都是类似 `layout` 属性定义的数据结构,值必须为 `Array`,其数据项为 `Object`。例如: `{lg: [layout items], md: [layout items]}`。需要注意的是,在创建栅格布局后设置该属性无效。
+
* **colNum**
-
+
* type: `Number`
* required: `false`
* default: `12`
@@ -182,7 +190,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
定义栅格系统的列数,其值需为自然数。
* **rowHeight**
-
+
* type: `Number`
* required: `false`
* default: `150`
@@ -190,7 +198,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
每行的高度,单位像素。
* **maxRows**
-
+
* type: `Number`
* required: `false`
* default: `Infinity`
@@ -198,7 +206,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
定义最大行数。
* **margin**
-
+
* type: `Array`
* required: `false`
* default: `[10, 10]`
@@ -208,7 +216,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
值必须是包含两个 `Number`的数组,数组中第一个元素表示水平边距,第二个表示垂直边距,单位为像素。
* **isDraggable**
-
+
* type: `Boolean`
* required: `false`
* default: `true`
@@ -216,7 +224,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识栅格中的元素是否可拖拽。
* **isResizable**
-
+
* type: `Boolean`
* required: `false`
* default: `true`
@@ -224,7 +232,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识栅格中的元素是否可调整大小。
* **isMirrored**
-
+
* type: `Boolean`
* required: `false`
* default: `false`
@@ -232,7 +240,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识栅格中的元素是否可镜像反转。
* **autoSize**
-
+
* type: `Boolean`
* required: `false`
* default: `true`
@@ -240,7 +248,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识容器是否自动调整大小。
* **verticalCompact**
-
+
* type: `Boolean`
* required: `false`
* default: `true`
@@ -248,7 +256,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识布局是否垂直压缩。
* **useCssTransforms**
-
+
* type: `Boolean`
* required: `false`
* default: `true`
@@ -256,7 +264,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识是否使用CSS属性 `transition-property: transform;`。
* **responsive**
-
+
* type: `Boolean`
* required: `false`
* default: `false`
@@ -269,7 +277,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
* required: `false`
* default: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }
- 为响应式布局设置断点。
+ 为响应式布局设置断点,其中参数代表不同设备的宽度:lg(large),md(medium),sm(small),xs(extra small)。
* **cols**
@@ -279,86 +287,100 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
设置每个断点对应的列数。
+* **useStyleCursor**
+
+ * type: `Boolean`
+ * required: `false`
+ * default: `true`
+
+ 标识是否使用动态鼠标指针样式。当拖动出现卡顿时,将此值设为 `false`也许可以缓解布局问题。
+
+ * **preventCollision**
+
+ * type: `Boolean`
+ * default: `false`
+
+ 值设置为ture时,栅格只能拖动至空白处。
##### GridItem
* **i**
-
+
* type: `String`
* required: `true`
栅格中元素的ID。
* **x**
-
+
* type: `Number`
* required: `true`
标识栅格元素位于第几列,需为自然数。
* **y**
-
+
* type: `Number`
* required: `true`
标识栅格元素位于第几行,需为自然数。
* **w**
-
+
* type: `Number`
* required: `true`
标识栅格元素的初始宽度,值为`colWidth`的倍数。
* **h**
-
+
* type: `Number`
* required: `true`
标识栅格元素的初始高度,值为`rowHeight`的倍数。
* **minW**
-
+
* type: `Number`
* required: `false`
* default: `1`
栅格元素的最小宽度,值为`colWidth`的倍数。
-
+
如果`w`小于`minW`,则`minW`的值会被`w`覆盖。
* **minH**
-
+
* type: `Number`
* required: `false`
* default: `1`
栅格元素的最小高度,值为`rowHeight`的倍数。
-
+
如果`h`小于`minH`,则`minH`的值会被`h`覆盖。
* **maxW**
-
+
* type: `Number`
* required: `false`
* default: `Infinity`
栅格元素的最大宽度,值为`colWidth`的倍数。
-
+
如果`w`大于`maxW`,则`maxW`的值会被`w`覆盖。
* **maxH**
-
+
* type: `Number`
* required: `false`
* default: `Infinity`
栅格元素的最大高度,值为`rowHeight`的倍数。
-
+
如果`h`大于`maxH`,则`maxH`的值会被`h`覆盖。
* **isDraggable**
-
+
* type: `Boolean`
* required: `false`
* default: `null`
@@ -366,7 +388,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识栅格元素是否可拖拽。如果值为`null`则取决于父容器。
* **isResizable**
-
+
* type: `Boolean`
* required: `false`
* default: `null`
@@ -374,7 +396,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识栅格元素是否可调整大小。如果值为`null`则取决于父容器。
* **static**
-
+
* type: `Boolean`
* required: `false`
* default: `false`
@@ -382,7 +404,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
标识栅格元素是否为静态的(无法拖拽、调整大小或被其他元素移动)。
* **dragIgnoreFrom**
-
+
* type: `String`
* required: `false`
* default: `'a, button'`
@@ -392,7 +414,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
请参考 [interact.js docs](http://interactjs.io/docs/#ignorable-selectors)中的`ignoreFrom`。
* **dragAllowFrom**
-
+
* type: `String`
* required: `false`
* default: `null`
@@ -404,7 +426,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
请参考 [interact.js docs](http://interactjs.io/docs/#ignorable-selectors)中的`allowFrom`。
* **resizeIgnoreFrom**
-
+
* type: `String`
* required: `false`
* default: `'a, button'`
@@ -419,7 +441,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
每一个栅格元素`grid-item`上都可以添加监听器,用于监听移动和调整大小事件,这样父级Vue对象就可以收到通知。
- [示例](https://jbaysolutions.github.io/vue-grid-layout/examples/02-events.html)
+ [示例](https://jbaysolutions.github.io/vue-grid-layout/examples/02-events.html)
````html
@@ -453,7 +475,7 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
{{item.i}}
-````
+````
* **layoutCreatedEvent**
@@ -518,12 +540,12 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
* **resizeEvent**
调整大小时的事件
-
+
```javascript
resizeEvent: function(i, newH, newW, newHPx, newWPx){
console.log("RESIZE i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
},
-```
+```
* **movedEvent**
@@ -538,21 +560,21 @@ Also check https://cli.vuejs.org/guide/build-targets.html#library
* **resizedEvent**
调整大小后的事件
-
+
```javascript
/**
- *
+ *
* @param i the item id/index
- * @param newH new height in grid rows
+ * @param newH new height in grid rows
* @param newW new width in grid columns
* @param newHPx new height in pixels
* @param newWPx new width in pixels
- *
+ *
*/
resizedEvent: function(i, newH, newW, newHPx, newWPx){
console.log("RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
},
-```
+```
## 如何贡献
diff --git a/README.md b/README.md
index e15c7d3b..540b2231 100644
--- a/README.md
+++ b/README.md
@@ -1,50 +1,26 @@
+
0&&(this.layout.length>this.originalLayout.length?this.originalLayout=this.originalLayout.concat(e):this.originalLayout=this.originalLayout.filter((function(t){return!e.some((function(e){return t.i===e.i}))}))),this.lastLayoutLength=this.layout.length,this.initResponsiveFeatures()}d(this.layout,this.verticalCompact),this.eventBus.$emit("updateWidth",this.width),this.updateHeight()}},updateHeight:function(){this.mergedStyle={height:this.containerHeight()}},onWindowResize:function(){null!==this.$refs&&null!==this.$refs.item&&void 0!==this.$refs.item&&(this.width=this.$refs.item.offsetWidth),this.eventBus.$emit("resizeEvent")},containerHeight:function(){if(this.autoSize)return u(this.layout)*(this.rowHeight+this.margin[1])+this.margin[1]+"px"},dragEvent:function(e,t,n,r,i,o){var a=h(this.layout,t);void 0!==a&&null!==a||(a={x:0,y:0}),"dragmove"===e||"dragstart"===e?(this.placeholder.i=t,this.placeholder.x=a.x,this.placeholder.y=a.y,this.placeholder.w=o,this.placeholder.h=i,this.$nextTick((function(){this.isDragging=!0})),this.eventBus.$emit("updateWidth",this.width)):this.$nextTick((function(){this.isDragging=!1})),this.layout=b(this.layout,a,n,r,!0,this.preventCollision),d(this.layout,this.verticalCompact),this.eventBus.$emit("compact"),this.updateHeight(),"dragend"===e&&this.$emit("layout-updated",this.layout)},resizeEvent:function(e,t,n,r,i,o){var a,s=h(this.layout,t);if(void 0!==s&&null!==s||(s={h:0,w:0}),this.preventCollision){var u=y(this.layout,K({},s,{w:o,h:i})).filter((function(e){return e.i!==s.i}));if(a=u.length>0,a){var l=1/0,c=1/0;u.forEach((function(e){e.x>s.x&&(l=Math.min(l,e.x)),e.y>s.y&&(c=Math.min(c,e.y))})),Number.isFinite(l)&&(s.w=l-s.x),Number.isFinite(c)&&(s.h=c-s.y)}}a||(s.w=o,s.h=i),"resizestart"===e||"resizemove"===e?(this.placeholder.i=t,this.placeholder.x=n,this.placeholder.y=r,this.placeholder.w=s.w,this.placeholder.h=s.h,this.$nextTick((function(){this.isDragging=!0})),this.eventBus.$emit("updateWidth",this.width)):this.$nextTick((function(){this.isDragging=!1})),this.responsive&&this.responsiveGridLayout(),d(this.layout,this.verticalCompact),this.eventBus.$emit("compact"),this.updateHeight(),"resizeend"===e&&this.$emit("layout-updated",this.layout)},responsiveGridLayout:function(){var e=q(this.breakpoints,this.width),t=U(e,this.cols);null==this.lastBreakpoint||this.layouts[this.lastBreakpoint]||(this.layouts[this.lastBreakpoint]=l(this.layout));var n=Z(this.originalLayout,this.layouts,this.breakpoints,e,this.lastBreakpoint,t,this.verticalCompact);this.layouts[e]=n,this.$emit("update:layout",n),this.lastBreakpoint=e,this.eventBus.$emit("setColNum",U(e,this.cols))},initResponsiveFeatures:function(){this.layouts={}},findDifference:function(e,t){var n=e.filter((function(e){return!t.some((function(t){return e.i===t.i}))})),r=t.filter((function(t){return!e.some((function(e){return t.i===e.i}))}));return n.concat(r)}}},ne=te,re=(n("e279"),L(ne,X,Y,!1,null,null,null)),ie=re.exports,oe={GridLayout:ie,GridItem:B};Object.keys(oe).forEach((function(e){o.a.component(e,oe[e])}));var ae=oe;n.d(t,"GridLayout",(function(){return ie})),n.d(t,"GridItem",(function(){return B}));t["default"]=ae},fb3a:function(e,t,n){(function(t){e.exports=t()})((function(){var e=function(e){var t;return function(n){return t||e(t={exports:{},parent:n},t.exports),t.exports}},t=e((function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Scope=t.ActionName=void 0;var r=v(tn),i=d(f),o=d(Sn),a=d(kn),s=d(Bn),u=d(or),l=d(jr),c=d(n({}));function d(e){return e&&e.__esModule?e:{default:e}}function p(){if("function"!==typeof WeakMap)return null;var e=new WeakMap;return p=function(){return e},e}function v(e){if(e&&e.__esModule)return e;var t=p();if(t&&t.has(e))return t.get(e);var n={};if(null!=e){var r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if(Object.prototype.hasOwnProperty.call(e,i)){var o=r?Object.getOwnPropertyDescriptor(e,i):null;o&&(o.get||o.set)?Object.defineProperty(n,i,o):n[i]=e[i]}}return n["default"]=e,t&&t.set(e,n),n}function h(e){return h="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},h(e)}function g(e,t){return!t||"object"!==h(t)&&"function"!==typeof t?y(e):t}function y(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function m(e,t,n){return m="undefined"!==typeof Reflect&&Reflect.get?Reflect.get:function(e,t,n){var r=b(e,t);if(r){var i=Object.getOwnPropertyDescriptor(r,t);return i.get?i.get.call(n):i.value}},m(e,t,n||e)}function b(e,t){while(!Object.prototype.hasOwnProperty.call(e,t))if(e=w(e),null===e)break;return e}function w(e){return w=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)},w(e)}function x(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&O(e,t)}function O(e,t){return O=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},O(e,t)}function P(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _(e,t){for(var n=0;n{t.autoStartHoldTimer=null},"autoStart:prepared":({interaction:t})=>{const e=Ve(t);e>0&&(t.autoStartHoldTimer=setTimeout(()=>{t.start(t.prepared,t.interactable,t.element)},e))},"interactions:move":({interaction:t,duplicate:e})=>{t.autoStartHoldTimer&&t.pointerWasMoved&&!e&&(clearTimeout(t.autoStartHoldTimer),t.autoStartHoldTimer=null)},"autoStart:before-start":({interaction:t})=>{const e=Ve(t);e>0&&(t.prepared.name=null)}},getHoldDuration:Ve};var Ze=Ue,Ke={id:"auto-start",install(t){t.usePlugin(Fe),t.usePlugin(Ze),t.usePlugin(Ye)}};function Je(t){const{defaults:e,actions:n}=t;t.autoScroll=Qe,Qe.now=()=>t.now(),n.phaselessTypes.autoscroll=!0,e.perAction.autoScroll=Qe.defaults}"object"===typeof window&&window&&Ee(window),Se.use(Ke);const Qe={defaults:{enabled:!1,margin:60,container:null,speed:300},now:Date.now,interaction:null,i:0,x:0,y:0,isScrolling:!1,prevTime:0,margin:0,speed:0,start(t){Qe.isScrolling=!0,V.cancel(Qe.i),t.autoScroll=Qe,Qe.interaction=t,Qe.prevTime=Qe.now(),Qe.i=V.request(Qe.scroll)},stop(){Qe.isScrolling=!1,Qe.interaction&&(Qe.interaction.autoScroll=null),V.cancel(Qe.i)},scroll(){const{interaction:t}=Qe,{interactable:e,element:n}=t,i=t.prepared.name,r=e.options[i].autoScroll,o=tn(r.container,e,n),s=Qe.now(),a=(s-Qe.prevTime)/1e3,c=r.speed*a;if(c>=1){const i={x:Qe.x*c,y:Qe.y*c};if(i.x||i.y){const r=en(o);R.window(o)?o.scrollBy(i.x,i.y):o&&(o.scrollLeft+=i.x,o.scrollTop+=i.y);const s=en(o),a={x:s.x-r.x,y:s.y-r.y};(a.x||a.y)&&e.fire({type:"autoscroll",target:n,interactable:e,delta:a,interaction:t,container:o})}Qe.prevTime=s}Qe.isScrolling&&(V.cancel(Qe.i),Qe.i=V.request(Qe.scroll))},check(t,e){var n;const i=t.options;return null==(n=i[e].autoScroll)?void 0:n.enabled},onInteractionMove({interaction:t,pointer:e}){if(!t.interacting()||!Qe.check(t.interactable,t.prepared.name))return;if(t.simulation)return void(Qe.x=Qe.y=0);let n,i,r,o;const{interactable:s,element:a}=t,c=t.prepared.name,l=s.options[c].autoScroll,u=tn(l.container,s,a);if(R.window(u))o=e.clientXGrid #1
+ Grid #2
+
+
+
+ [x, y, w, h]:
+
+ Draggable
+ Resizable
+ Responsive
+
+ [x, y, w, h]:
+ [x, y, w, h]:
+
+ [x, y, w, h]:
+
+ Draggable
+ Resizable
+ Bounded
+
+
+ API to generate image and PDF documents
+ Vue Grid Layout Example 5 - Mirrored grid layout
:is-mirrored="mirrored"
:vertical-compact="true"
:use-css-transforms="true"
- :right-to-left="true"
>