diff --git a/docs/examples-docs/zh-CN/sku.md b/docs/examples-docs/zh-CN/sku.md index 0a403b4d2..9899dca9d 100644 --- a/docs/examples-docs/zh-CN/sku.md +++ b/docs/examples-docs/zh-CN/sku.md @@ -101,7 +101,7 @@ Vue.component(Sku.name, Sku); - + 积分兑换 diff --git a/docs/src/doc.config.js b/docs/src/doc.config.js index 382792506..9c575bce2 100644 --- a/docs/src/doc.config.js +++ b/docs/src/doc.config.js @@ -2,18 +2,16 @@ module.exports = { "zh-CN": { header: { - '首页': 'https://www.youzanyun.com/zanui', - 'PC端': 'https://www.youzanyun.com/zanui/react', - '移动端': 'https://www.youzanyun.com/zanui/vue', - '微信小程序': 'https://github.com/youzan/zanui-weapp', - 'English': '#/en-US/' + Github: 'https://github.com/youzan/vant', + English: '#/en-US/' }, footer: { github: 'https://github.com/youzan/vant', nav: { - '有赞官网': 'https://www.youzan.com/', - '加入我们': 'https://job.youzan.com/', - '意见反馈': 'https://github.com/youzan/vant/issues' + 'React': 'https://www.youzanyun.com/zanui/react', + '微信小程序': 'https://github.com/youzan/zanui-weapp', + '意见反馈': 'https://github.com/youzan/vant/issues', + '开发指南': 'https://github.com/youzan/vant/blob/dev/docs/examples-docs/zh-CN/contribute.md' } }, nav: [ @@ -259,18 +257,16 @@ module.exports = { }, "en-US": { header: { - 'Homepage': 'https://www.youzanyun.com/zanui', - 'PC': 'https://www.youzanyun.com/zanui/react', - 'Mobile': 'https://www.youzanyun.com/zanui/vue', - 'Weapp': 'https://github.com/youzan/zanui-weapp', + Github: 'https://github.com/youzan/vant', '中文': '#/zh-CN' }, footer: { github: 'https://github.com/youzan/vant', nav: { - 'Youzan': 'https://www.youzan.com/', - 'Join us': 'https://job.youzan.com/', - 'Feedback': 'https://github.com/youzan/vant/issues' + 'React': 'https://www.youzanyun.com/zanui/react', + 'Weapp': 'https://github.com/youzan/zanui-weapp', + 'Feedback': 'https://github.com/youzan/vant/issues', + 'Contribute': 'https://github.com/youzan/vant/blob/dev/docs/examples-docs/en-US/contribute.md' } }, nav: [ diff --git a/package.json b/package.json index 8b51d0215..375f117f8 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "vue-lazyload": "^1.1.3" }, "peerDependencies": { - "vue": "^2.4.4" + "vue": ">= 2.4.0" }, "devDependencies": { "autoprefixer": "^7.1.3", @@ -65,7 +65,7 @@ "babel-preset-env": "^1.6.0", "chai": "^4.1.2", "cheerio": "^0.22.0", - "codecov": "^2.2.0", + "codecov": "^2.3.1", "cross-env": "^5.0.5", "css-loader": "^0.28.7", "eslint-plugin-vue": "^2.1.0", @@ -97,7 +97,7 @@ "postcss": "^6.0.10", "postcss-calc": "^6.0.0", "postcss-easy-import": "^3.0.0", - "postcss-loader": "^2.0.6", + "postcss-loader": "^2.0.8", "precss": "2.0.0", "progress-bar-webpack-plugin": "^1.10.0", "rimraf": "^2.5.4", @@ -107,16 +107,16 @@ "style-loader": "^0.19.0", "uppercamelcase": "^3.0.0", "url-loader": "^0.6.2", - "vue": "^2.4.2", + "vue": "^2.5.2", "vue-loader": "^13.3.0", - "vue-markdown-loader": "^2.1.0", - "vue-router": "^3.0.0", + "vue-markdown-loader": "^2.2.2", + "vue-router": "^3.0.1", "vue-sfc-compiler": "^0.0.2", "vue-style-loader": "^3.0.0", - "vue-template-compiler": "^2.4.2", + "vue-template-compiler": "^2.5.2", "webpack": "^3.7.1", "webpack-bundle-analyzer": "^2.9.0", - "webpack-dev-server": "^2.7.1", + "webpack-dev-server": "^2.9.2", "webpack-merge": "^4.1.0", "zan-doc": "^0.3.6" } diff --git a/packages/mixins/popup/index.js b/packages/mixins/popup/index.js index 52317cbe2..208833abd 100644 --- a/packages/mixins/popup/index.js +++ b/packages/mixins/popup/index.js @@ -1,9 +1,9 @@ -import PopupManager from './popup-manager'; -import PopupContext from './popup-context'; +import manager from './popup-manager'; +import context from './popup-context'; export default { props: { - // popup当前显示状态 + // popup 当前显示状态 value: { type: Boolean, default: false @@ -13,16 +13,13 @@ export default { type: Boolean, default: false }, - /** - * 点击遮罩层是否关闭popup - */ + // 点击遮罩层是否关闭 popup closeOnClickOverlay: { type: Boolean, default: false }, zIndex: [String, Number], - // popup滚动时是否body内容也滚动 - // 默认为不滚动 + // popup 滚动时是否禁用 body 滚动 lockOnScroll: { type: Boolean, default: true @@ -36,27 +33,18 @@ export default { watch: { value(val) { - if (val) { - if (this.opening) return; - this.open(); - } else { - if (this.closing) return; - this.close(); - } + this[val ? 'open' : 'close'](); } }, beforeMount() { - this._popupId = 'popup-' + PopupContext.plusKeyByOne('idSeed'); - PopupManager.register(this._popupId, this); + this._popupId = 'popup-' + context.plusKeyByOne('idSeed'); + context.instances[this._popupId] = this; }, data() { return { - opening: false, opened: false, - closing: false, - bodyOverflow: null, pos: { x: 0, y: 0 @@ -71,6 +59,7 @@ export default { y: e.touches[0].clientY }; }, + watchTouchMove(e) { const pos = this.pos; const dx = e.touches[0].clientX - pos.x; @@ -95,47 +84,28 @@ export default { e.stopPropagation(); } }, - /** - * 显示popup - */ - open() { - /* istanbul ignore if */ - if (this.$isServer) return; - if (this.opened) return; - this.opening = true; + open() { + if (this.opened || this.$isServer) { + return; + } this.$emit('input', true); - const zIndex = this.zIndex; - - // 如果属性中传入了`zIndex`,则覆盖`popupContext`中对应的`zIndex` - if (zIndex) { - PopupContext.setContext('zIndex', zIndex); + // 如果属性中传入了`zIndex`,则覆盖`context`中对应的`zIndex` + if (this.zIndex !== undefined) { + context.zIndex = this.zIndex; } - // 如果显示遮罩层 if (this.overlay) { - if (this.closing) { - PopupManager.closeModal(this._popupId); - this.closing = false; - } - PopupManager.openModal(this._popupId, PopupManager.nextZIndex(), this.$el); - - // 如果滚动时需要锁定 + manager.openModal(this._popupId, context.plusKeyByOne('zIndex'), this.$el); if (this.lockOnScroll) { - // 将原来的`bodyOverflow`存起来 - if (!this.bodyOverflow) { - this.bodyOverflow = document.body.style.overflow; - } - - document.body.style.overflow = 'hidden'; + document.body.classList.add('van-overflow-hidden'); } } - this.$el.style.zIndex = PopupManager.nextZIndex(); + this.$el.style.zIndex = context.plusKeyByOne('zIndex'); this.opened = true; - this.opening = false; if (this.preventScroll) { document.addEventListener('touchstart', this.recordPosition, false); @@ -143,23 +113,15 @@ export default { } }, - /** - * 关闭popup - */ close() { - if (this.closing) return; - - this.closing = true; + if (!this.opened || this.$isServer) { + return; + } this.$emit('input', false); if (this.lockOnScroll) { - setTimeout(() => { - if (this.overlay && this.bodyOverflow !== 'hidden') { - document.body.style.overflow = this.bodyOverflow; - } - this.bodyOverflow = null; - }, 200); + document.body.classList.remove('van-overflow-hidden'); } this.opened = false; @@ -167,8 +129,7 @@ export default { }, doAfterClose() { - this.closing = false; - PopupManager.closeModal(this._popupId); + manager.closeModal(this._popupId); if (this.preventScroll) { document.removeEventListener('touchstart', this.recordPosition, false); @@ -178,12 +139,10 @@ export default { }, beforeDestroy() { - PopupManager.deregister(this._popupId); - PopupManager.closeModal(this._popupId); - - if (this.overlay && this.bodyOverflow !== null && this.bodyOverflow !== 'hidden') { - document.body.style.overflow = this.bodyOverflow; + context.instances[this._popupId] = null; + manager.closeModal(this._popupId); + if (this.lockOnScroll) { + document.body.classList.remove('van-overflow-hidden'); } - this.bodyOverflow = null; } }; diff --git a/packages/mixins/popup/popup-context.js b/packages/mixins/popup/popup-context.js index 0e0588b7b..81035f451 100644 --- a/packages/mixins/popup/popup-context.js +++ b/packages/mixins/popup/popup-context.js @@ -1,35 +1,15 @@ -import Vue from 'vue'; - -const _global = Vue.prototype.$isServer ? global : window; - -const DEFAULT_CONTEXT = { +const PopupContext = { idSeed: 1, zIndex: 2000, - hasModal: false, instances: {}, - modalStack: [] -}; - -if (!_global.popupContext) { - _global.popupContext = { - ...DEFAULT_CONTEXT - }; -} - -const PopupContext = { - getContext(key) { - return _global.popupContext[key]; - }, - - setContext(key, value) { - _global.popupContext[key] = value; - }, + modalStack: [], plusKeyByOne(key) { - const oldVal = +_global.popupContext[key]; - _global.popupContext[key] = oldVal + 1; + return this[key]++; + }, - return oldVal; + get topModal() { + return this.modalStack[this.modalStack.length - 1]; } }; diff --git a/packages/mixins/popup/popup-manager.js b/packages/mixins/popup/popup-manager.js index 4c71dfc99..62ebc8c6c 100644 --- a/packages/mixins/popup/popup-manager.js +++ b/packages/mixins/popup/popup-manager.js @@ -1,133 +1,68 @@ -import Vue from 'vue'; -import PopupContext from './popup-context'; - -const getModal = function() { - if (Vue.prototype.$isServer) return; - let modalDom = PopupContext.getContext('modalDom'); - - if (modalDom) { - PopupContext.setContext('hasModal', true); - } else { - PopupContext.setContext('hasModal', false); - - modalDom = document.createElement('div'); - PopupContext.setContext('modalDom', modalDom); - - modalDom.addEventListener('touchmove', function(event) { - event.preventDefault(); - event.stopPropagation(); - }); - - modalDom.addEventListener('click', function() { - PopupManager.handleOverlayClick && PopupManager.handleOverlayClick(); - }); - } - - return modalDom; -}; +import context from './popup-context'; const PopupManager = { - nextZIndex() { - return PopupContext.plusKeyByOne('zIndex'); - }, + getModal() { + let { modal } = context; - getInstance(id) { - return PopupContext.getContext('instances')[id]; - }, + if (!modal) { + modal = document.createElement('div'); + modal.classList.add('van-modal'); + modal.addEventListener('touchmove', event => { + event.preventDefault(); + event.stopPropagation(); + }); + modal.addEventListener('click', () => { + PopupManager.handleOverlayClick(); + }); - register(id, instance) { - if (id && instance) { - const instances = PopupContext.getContext('instances'); - instances[id] = instance; + context.modal = modal; } + + return modal; }, - deregister(id) { - if (id) { - const instances = PopupContext.getContext('instances'); - instances[id] = null; - delete instances[id]; - } - }, - - /** - * 遮罩层点击回调,`closeOnClickOverlay`为`true`时会关闭当前`popup` - */ + // close popup when click modal && closeOnClickOverlay is true handleOverlayClick() { - const modalStack = PopupContext.getContext('modalStack'); - const topModal = modalStack[modalStack.length - 1]; - if (!topModal) return; - - const instance = PopupManager.getInstance(topModal.id); - if (instance && instance.closeOnClickOverlay) { - instance.close(); + const { topModal } = context; + if (topModal) { + const instance = context.instances[topModal.id]; + if (instance && instance.closeOnClickOverlay) { + instance.close(); + } } }, openModal(id, zIndex, dom) { - if (!id || zIndex === undefined) return; + const { modalStack } = context; + const exist = modalStack.some(item => item.id === id); - const modalStack = PopupContext.getContext('modalStack'); + if (!exist) { + const modal = this.getModal(); + modal.style.zIndex = zIndex; - for (let i = 0, len = modalStack.length; i < len; i++) { - const item = modalStack[i]; - if (item.id === id) { - return; - } - } - - const modalDom = getModal(); - - modalDom.classList.add('van-modal'); - - let domParentNode; - if (dom && dom.parentNode && dom.parentNode.nodeType !== 11) { - domParentNode = dom.parentNode; - } else { - domParentNode = document.body; - } - domParentNode.appendChild(modalDom); - - if (zIndex) { - modalDom.style.zIndex = zIndex; - } - modalDom.style.display = ''; - - modalStack.push({ id: id, zIndex: zIndex, parentNode: domParentNode }); + const parentNode = dom && dom.parentNode && dom.parentNode.nodeType !== 11 ? dom.parentNode : document.body; + parentNode.appendChild(modal); + modalStack.push({ id, zIndex, parentNode }); + }; }, closeModal(id) { - const modalStack = PopupContext.getContext('modalStack'); - const modalDom = getModal(); + const { modalStack } = context; - if (modalStack.length > 0) { - const topItem = modalStack[modalStack.length - 1]; - if (topItem.id === id) { + if (modalStack.length) { + if (context.topModal.id === id) { + const modal = this.getModal(); modalStack.pop(); - if (modalStack.length > 0) { - modalDom.style.zIndex = modalStack[modalStack.length - 1].zIndex; - modalDom.parentNode.removeChild(modalDom); - const currModalParent = modalStack[0].parentNode; - currModalParent && currModalParent.appendChild(modalDom); + modal.parentNode.removeChild(modal); + if (modalStack.length) { + const { topModal } = context; + modal.style.zIndex = topModal.zIndex; + topModal.parentNode.appendChild(modal); } } else { - for (let i = modalStack.length - 1; i >= 0; i--) { - if (modalStack[i].id === id) { - modalStack.splice(i, 1); - break; - } - } + context.modalStack = modalStack.filter(item => item.id !== id); } } - - if (modalStack.length === 0) { - setTimeout(() => { - if (modalDom.parentNode) modalDom.parentNode.removeChild(modalDom); - - modalDom.style.display = 'none'; - this.modalDom = null; - }, 200); - } } }; diff --git a/packages/popup/index.vue b/packages/popup/index.vue index 7fe9dbf7a..3a39f2e27 100644 --- a/packages/popup/index.vue +++ b/packages/popup/index.vue @@ -1,6 +1,6 @@ - + @@ -8,29 +8,23 @@