From 82bb27896ea03ea4d1a8f588bc59163205952b63 Mon Sep 17 00:00:00 2001 From: cookfront Date: Wed, 15 Feb 2017 21:03:07 +0800 Subject: [PATCH 1/8] popup component --- components.json | 3 +- docs/examples/popup.md | 84 +++++++++++++ docs/nav.config.json | 4 +- packages/popup/CHANGELOG.md | 8 ++ packages/popup/README.md | 26 ++++ packages/popup/index.js | 3 + packages/popup/package.json | 10 ++ packages/popup/src/popup.vue | 71 +++++++++++ packages/zanui/src/index.pcss | 1 + packages/zanui/src/popup.pcss | 75 ++++++++++++ src/index.js | 5 +- src/mixins/popup/index.js | 194 ++++++++++++++++++++++++++++++ src/mixins/popup/popup-manager.js | 133 ++++++++++++++++++++ src/utils/dom.js | 45 +++++++ src/utils/merge.js | 15 +++ 15 files changed, 673 insertions(+), 4 deletions(-) create mode 100644 docs/examples/popup.md create mode 100644 packages/popup/CHANGELOG.md create mode 100644 packages/popup/README.md create mode 100644 packages/popup/index.js create mode 100644 packages/popup/package.json create mode 100644 packages/popup/src/popup.vue create mode 100644 packages/zanui/src/popup.pcss create mode 100644 src/mixins/popup/index.js create mode 100644 src/mixins/popup/popup-manager.js create mode 100644 src/utils/dom.js create mode 100644 src/utils/merge.js diff --git a/components.json b/components.json index fa7c0daea..a11836bf4 100644 --- a/components.json +++ b/components.json @@ -5,5 +5,6 @@ "radio": "./packages/radio/index.js", "cell": "./packages/cell/index.js", "icon": "./packages/icon/index.js", - "cell-group": "./packages/cell-group/index.js" + "cell-group": "./packages/cell-group/index.js", + "popup": "./packages/popup/index.js" } diff --git a/docs/examples/popup.md b/docs/examples/popup.md new file mode 100644 index 000000000..e5ca59b0b --- /dev/null +++ b/docs/examples/popup.md @@ -0,0 +1,84 @@ + + + + +## Popup组件 + +### 基础用法 + +:::demo +```html +从下方弹出popup + + xxxx + + +从上方方弹出popup + + 更新成功 + + +从右方弹出popup + + 关闭 popup + + +从中间弹出popup + + 一些内容 + +``` +::: + +### API + +| 参数 | 说明 | 类型 | 默认值 | 可选值 | +|-----------|-----------|-----------|-------------|-------------| +| value | 利用`v-model`绑定当前组件是否显示 | Boolean | '' | | \ No newline at end of file diff --git a/docs/nav.config.json b/docs/nav.config.json index 28b555022..38c9aee7c 100644 --- a/docs/nav.config.json +++ b/docs/nav.config.json @@ -77,8 +77,8 @@ "title": "Lazyload" }, { - "path": "/pop", - "title": "Pop" + "path": "/popup", + "title": "Popup" }, { "path": "/swipe", diff --git a/packages/popup/CHANGELOG.md b/packages/popup/CHANGELOG.md new file mode 100644 index 000000000..e88c472b3 --- /dev/null +++ b/packages/popup/CHANGELOG.md @@ -0,0 +1,8 @@ +## 0.0.2 (2017-01-20) + +* 改了bug A +* 加了功能B + +## 0.0.1 (2017-01-10) + +* 第一版 diff --git a/packages/popup/README.md b/packages/popup/README.md new file mode 100644 index 000000000..4c6172563 --- /dev/null +++ b/packages/popup/README.md @@ -0,0 +1,26 @@ +# @youzan/<%= name %> + +!!! 请在此处填写你的文档最简单描述 !!! + +[![version][version-image]][download-url] +[![download][download-image]][download-url] + +[version-image]: http://npm.qima-inc.com/badge/v/@youzan/<%= name %>.svg?style=flat-square +[download-image]: http://npm.qima-inc.com/badge/d/@youzan/<%= name %>.svg?style=flat-square +[download-url]: http://npm.qima-inc.com/package/@youzan/<%= name %> + +## Demo + +## Usage + +## API + +| 参数 | 说明 | 类型 | 默认值 | 可选值 | +|-----------|-----------|-----------|-------------|-------------| +| className | 自定义额外类名 | string | '' | '' | + + + + +## License +[MIT](https://opensource.org/licenses/MIT) diff --git a/packages/popup/index.js b/packages/popup/index.js new file mode 100644 index 000000000..31857d9ef --- /dev/null +++ b/packages/popup/index.js @@ -0,0 +1,3 @@ +import Popup from './src/popup'; + +export default Popup; diff --git a/packages/popup/package.json b/packages/popup/package.json new file mode 100644 index 000000000..7dbfa2900 --- /dev/null +++ b/packages/popup/package.json @@ -0,0 +1,10 @@ +{ + "name": "<%= name %>", + "version": "<%= version %>", + "description": "<%= description %>", + "main": "./lib/index.js", + "author": "<%= author %>", + "license": "<%= license %>", + "devDependencies": {}, + "dependencies": {} +} diff --git a/packages/popup/src/popup.vue b/packages/popup/src/popup.vue new file mode 100644 index 000000000..1f27a2f25 --- /dev/null +++ b/packages/popup/src/popup.vue @@ -0,0 +1,71 @@ + + + diff --git a/packages/zanui/src/index.pcss b/packages/zanui/src/index.pcss index 469e089fc..554cafe0f 100644 --- a/packages/zanui/src/index.pcss +++ b/packages/zanui/src/index.pcss @@ -5,4 +5,5 @@ @import './cell.pcss'; @import './field.pcss'; @import './icon.pcss'; +@import './popup.pcss'; @import './switch.pcss'; diff --git a/packages/zanui/src/popup.pcss b/packages/zanui/src/popup.pcss new file mode 100644 index 000000000..52798154f --- /dev/null +++ b/packages/zanui/src/popup.pcss @@ -0,0 +1,75 @@ +.v-modal { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: rgba(0, 0, 0, 0.701961); +} + +@component-namespace o2 { + @component popup { + position: fixed; + background-color: #fff; + top: 50%; + left: 50%; + transform: translate3d(-50%, -50%, 0); + backface-visibility: hidden; + transition: .2s ease-out; + + @modifier top { + top: 0; + right: auto; + bottom: auto; + left: 50%; + transform: translate3d(-50%, 0, 0); + } + + @modifier right { + top: 50%; + right: 0; + bottom: auto; + left: auto; + transform: translate3d(0, -50%, 0); + } + + @modifier bottom { + top: auto; + bottom: 0; + right: auto; + left: 50%; + transform: translate3d(-50%, 0, 0); + } + + @modifier left { + top: 50%; + right: auto; + bottom: auto; + left: 0; + transform: translate3d(0, -50%, 0); + } + } +} + +.popup-slide-top-enter, +.popup-slide-top-leave-active { + transform: translate3d(-50%, -100%, 0); +} + +.popup-slide-right-enter, +.popup-slide-right-leave-active { + transform: translate3d(100%, -50%, 0); +} + +.popup-slide-bottom-enter, +.popup-slide-bottom-leave-active { + transform: translate3d(-50%, 100%, 0); +} + +.popup-slide-left-enter, .popup-slide-left-leave-active { + transform: translate3d(-100%, -50%, 0); +} + +.popup-fade-enter, .popup-fade-leave-active { + opacity: 0; +} diff --git a/src/index.js b/src/index.js index 3ffa774fd..42ea5ca67 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import Radio from '../packages/radio/index.js'; import Cell from '../packages/cell/index.js'; import Icon from '../packages/icon/index.js'; import CellGroup from '../packages/cell-group/index.js'; +import Popup from '../packages/popup/index.js'; // zanui import '../packages/zanui/src/index.pcss'; @@ -18,6 +19,7 @@ const install = function(Vue) { Vue.component(Cell.name, Cell); Vue.component(Icon.name, Icon); Vue.component(CellGroup.name, CellGroup); + Vue.component(Popup.name, Popup); }; // auto install @@ -34,5 +36,6 @@ module.exports = { Radio, Cell, Icon, - CellGroup + CellGroup, + Popup }; diff --git a/src/mixins/popup/index.js b/src/mixins/popup/index.js new file mode 100644 index 000000000..103a1d44a --- /dev/null +++ b/src/mixins/popup/index.js @@ -0,0 +1,194 @@ +import Vue from 'vue'; +import merge from 'src/utils/merge'; +import PopupManager from './popup-manager'; + +let idSeed = 1; + +const getDOM = function(dom) { + if (dom.nodeType === 3) { + dom = dom.nextElementSibling || dom.nextSibling; + getDOM(dom); + } + return dom; +}; + +let scrollBarWidth; +const getScrollBarWidth = () => { + if (Vue.prototype.$isServer) return; + if (scrollBarWidth !== undefined) return scrollBarWidth; + + const outer = document.createElement('div'); + outer.style.visibility = 'hidden'; + outer.style.width = '100px'; + outer.style.position = 'absolute'; + outer.style.top = '-9999px'; + document.body.appendChild(outer); + + const widthNoScroll = outer.offsetWidth; + outer.style.overflow = 'scroll'; + + const inner = document.createElement('div'); + inner.style.width = '100%'; + outer.appendChild(inner); + + const widthWithScroll = inner.offsetWidth; + outer.parentNode.removeChild(outer); + + return widthNoScroll - widthWithScroll; +}; + +export default { + props: { + /** + * popup当前显示状态 + */ + value: { + type: Boolean, + default: false + }, + /** + * 是否显示遮罩层 + */ + overlay: { + type: Boolean, + default: false + }, + /** + * 点击遮罩层是否关闭popup + */ + closeOnClickOverlay: { + type: Boolean, + default: false + }, + zIndex: [String, Number], + /** + * popup滚动时是否body内容也滚动 + * 默认为不滚动 + */ + lockOnScroll: { + type: Boolean, + default: true + } + }, + + watch: { + value(val) { + if (val) { + if (this.opening) return; + + if (!this.rendered) { + this.rendered = true; + Vue.nextTick(() => { + this.open(); + }); + } else { + this.open(); + } + } else { + this.close(); + } + } + }, + + beforeMount() { + this._popupId = 'popup-' + idSeed++; + PopupManager.register(this._popupId, this); + }, + + data() { + return { + opening: false, + opened: false, + closing: false, + bodyOverflow: null, + bodyPaddingRight: null + }; + }, + + methods: { + /** + * 显示popup + */ + open(options) { + if (this.opened) return; + + this.opening = true; + + this.$emit('input', true); + + const dom = getDOM(this.$el); + const props = merge({}, this, options); + const overlay = props.overlay; + const zIndex = props.zIndex; + + // 如果属性中传入了`zIndex`,则覆盖`PopupManager`中对应的`zIndex` + if (zIndex) { + PopupManager.zIndex = zIndex; + } + + // 如果显示遮罩层 + if (overlay) { + if (this.closing) { + PopupManager.closeModal(this._popupId); + this.closing = false; + } + PopupManager.openModal(this._popupId, PopupManager.nextZIndex(), dom); + if (props.lockOnScroll) { + // 将原来的`bodyOverflow`和`bodyPaddingRight`存起来 + if (!this.bodyOverflow) { + this.bodyPaddingRight = document.body.style.paddingRight; + this.bodyOverflow = document.body.style.overflow; + } + scrollBarWidth = getScrollBarWidth(); + let bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight; + if (scrollBarWidth > 0 && bodyHasOverflow) { + document.body.style.paddingRight = scrollBarWidth + 'px'; + } + document.body.style.overlay = 'hidden'; + } + } + + dom.style.zIndex = PopupManager.nextZIndex(); + this.opened = true; + this.opening = false; + }, + + /** + * 关闭popup + */ + close() { + if (this.closing) return; + + this.closing = true; + + this.$emit('input', false); + + if (this.lockOnScroll) { + setTimeout(() => { + if (this.modal && this.bodyOverflow !== 'hidden') { + document.body.style.overflow = this.bodyOverflow; + document.body.style.paddingRight = this.bodyPaddingRight; + } + this.bodyOverflow = null; + this.bodyPaddingRight = null; + }, 200); + } + + PopupManager.closeModal(this._popupId); + this.opened = false; + this.closing = false; + } + }, + + beforeDestroy() { + PopupManager.deregister(this._popupId); + PopupManager.closeModal(this._popupId); + + if (this.modal && this.bodyOverflow !== null && this.bodyOverflow !== 'hidden') { + document.body.style.overflow = this.bodyOverflow; + document.body.style.paddingRight = this.bodyPaddingRight; + } + this.bodyOverflow = null; + this.bodyPaddingRight = null; + } +}; diff --git a/src/mixins/popup/popup-manager.js b/src/mixins/popup/popup-manager.js new file mode 100644 index 000000000..c339df3a9 --- /dev/null +++ b/src/mixins/popup/popup-manager.js @@ -0,0 +1,133 @@ +import { addClass, removeClass } from 'src/utils/dom'; + +let hasModal = false; + +const getModal = function() { + let modalDom = PopupManager.modalDom; + if (modalDom) { + hasModal = true; + } else { + hasModal = false; + modalDom = document.createElement('div'); + PopupManager.modalDom = modalDom; + + modalDom.addEventListener('touchmove', function(event) { + event.preventDefault(); + event.stopPropagation(); + }); + + modalDom.addEventListener('click', function() { + PopupManager.handleOverlayClick && PopupManager.handleOverlayClick(); + }); + } + + return modalDom; +}; + +const instances = {}; + +const PopupManager = { + zIndex: 2000, + + modalStack: [], + + nextZIndex() { + return this.zIndex++; + }, + + getInstance(id) { + return instances[id]; + }, + + register(id, instance) { + if (id && instance) { + instances[id] = instance; + } + }, + + deregister(id) { + if (id) { + instances[id] = null; + delete instances[id]; + } + }, + + handleOverlayClick() { + const topModal = PopupManager.modalStack[PopupManager.modalStack.length - 1]; + if (!topModal) return; + + const instance = PopupManager.getInstance(topModal.id); + if (instance && instance.closeOnClickOverlay) { + instance.close(); + } + }, + + openModal(id, zIndex, dom) { + if (!id || zIndex === undefined) return; + + const modalStack = this.modalStack; + + for (let i = 0, j = modalStack.length; i < j; i++) { + const item = modalStack[i]; + if (item.id === id) { + return; + } + } + + const modalDom = getModal(); + + addClass(modalDom, 'v-modal'); + setTimeout(() => { + removeClass(modalDom, 'v-modal-enter'); + }, 200); + + if (dom && dom.parentNode && dom.parentNode.nodeType !== 11) { + dom.parentNode.appendChild(modalDom); + } else { + document.body.appendChild(modalDom); + } + + if (zIndex) { + modalDom.style.zIndex = zIndex; + } + modalDom.style.display = ''; + + this.modalStack.push({ id: id, zIndex: zIndex }); + }, + + closeModal(id) { + const modalStack = this.modalStack; + const modalDom = getModal(); + + if (modalStack.length > 0) { + const topItem = modalStack[modalStack.length - 1]; + if (topItem.id === id) { + modalStack.pop(); + if (modalStack.length > 0) { + modalDom.style.zIndex = modalStack[modalStack.length - 1].zIndex; + } + } else { + for (let i = modalStack.length - 1; i >= 0; i--) { + if (modalStack[i].id === id) { + modalStack.splice(i, 1); + break; + } + } + } + } + + if (modalStack.length === 0) { + setTimeout(() => { + if (modalStack.length === 0) { + if (modalDom.parentNode) modalDom.parentNode.removeChild(modalDom); + + modalDom.style.display = 'none'; + this.modalDom = undefined; + } + removeClass(modalDom, 'v-modal-leave'); + }, 200); + } + } +}; + +export default PopupManager; diff --git a/src/utils/dom.js b/src/utils/dom.js new file mode 100644 index 000000000..0f7e6cb66 --- /dev/null +++ b/src/utils/dom.js @@ -0,0 +1,45 @@ +/* istanbul ignore next */ +export function addClass(el, cls) { + if (!el) return; + var curClass = el.className; + var classes = (cls || '').split(' '); + + for (var i = 0, j = classes.length; i < j; i++) { + var clsName = classes[i]; + if (!clsName) continue; + + if (el.classList) { + el.classList.add(clsName); + } else { + if (!hasClass(el, clsName)) { + curClass += ' ' + clsName; + } + } + } + if (!el.classList) { + el.className = curClass; + } +}; + +/* istanbul ignore next */ +export function removeClass(el, cls) { + if (!el || !cls) return; + var classes = cls.split(' '); + var curClass = ' ' + el.className + ' '; + + for (var i = 0, j = classes.length; i < j; i++) { + var clsName = classes[i]; + if (!clsName) continue; + + if (el.classList) { + el.classList.remove(clsName); + } else { + if (hasClass(el, clsName)) { + curClass = curClass.replace(' ' + clsName + ' ', ' '); + } + } + } + if (!el.classList) { + el.className = trim(curClass); + } +}; diff --git a/src/utils/merge.js b/src/utils/merge.js new file mode 100644 index 000000000..c0aa39a55 --- /dev/null +++ b/src/utils/merge.js @@ -0,0 +1,15 @@ +export default function(target, ...sources) { + for (let i = 1, j = sources.length; i < j; i++) { + let source = arguments[i] || {}; + for (let prop in source) { + if (source.hasOwnProperty(prop)) { + let value = source[prop]; + if (value !== undefined) { + target[prop] = value; + } + } + } + } + + return target; +}; From 4c3cdd433b701be3e7a1580be57f91de4fddcbc6 Mon Sep 17 00:00:00 2001 From: cookfront Date: Thu, 16 Feb 2017 15:12:28 +0800 Subject: [PATCH 2/8] dialog component --- build/bin/build-entry.js | 2 +- components.json | 3 +- docs/examples/dialog.md | 40 ++++++++++++++ docs/examples/popup.md | 2 +- docs/nav.config.json | 4 ++ packages/dialog/CHANGELOG.md | 8 +++ packages/dialog/README.md | 26 +++++++++ packages/dialog/index.js | 3 ++ packages/dialog/package.json | 10 ++++ packages/dialog/src/dialog.js | 98 ++++++++++++++++++++++++++++++++++ packages/dialog/src/dialog.vue | 63 ++++++++++++++++++++++ packages/zanui/src/dialog.pcss | 87 ++++++++++++++++++++++++++++++ packages/zanui/src/index.pcss | 1 + src/index.js | 5 +- src/utils/merge.js | 4 +- 15 files changed, 350 insertions(+), 6 deletions(-) create mode 100644 docs/examples/dialog.md create mode 100644 packages/dialog/CHANGELOG.md create mode 100644 packages/dialog/README.md create mode 100644 packages/dialog/index.js create mode 100644 packages/dialog/package.json create mode 100644 packages/dialog/src/dialog.js create mode 100644 packages/dialog/src/dialog.vue create mode 100644 packages/zanui/src/dialog.pcss diff --git a/build/bin/build-entry.js b/build/bin/build-entry.js index 2419df433..a976ee92e 100644 --- a/build/bin/build-entry.js +++ b/build/bin/build-entry.js @@ -51,7 +51,7 @@ ComponentNames.forEach(name => { 'Lazyload', // services - 'MessageBox', + 'Dialog', 'Toast', 'Indicator' ].indexOf(componentName) === -1) { diff --git a/components.json b/components.json index a11836bf4..1ed3e41c2 100644 --- a/components.json +++ b/components.json @@ -6,5 +6,6 @@ "cell": "./packages/cell/index.js", "icon": "./packages/icon/index.js", "cell-group": "./packages/cell-group/index.js", - "popup": "./packages/popup/index.js" + "popup": "./packages/popup/index.js", + "dialog": "./packages/dialog/index.js" } diff --git a/docs/examples/dialog.md b/docs/examples/dialog.md new file mode 100644 index 000000000..05fa69801 --- /dev/null +++ b/docs/examples/dialog.md @@ -0,0 +1,40 @@ + + +## Dialog组件 + +### 基础用法 + +:::demo +```html +alert + +confirm +``` +::: + +### API + +| 参数 | 说明 | 类型 | 默认值 | 可选值 | +|-----------|-----------|-----------|-------------|-------------| +| title | 标题 | String | '' | | +| message | 内容 | String | '' | | diff --git a/docs/examples/popup.md b/docs/examples/popup.md index e5ca59b0b..3778b530e 100644 --- a/docs/examples/popup.md +++ b/docs/examples/popup.md @@ -81,4 +81,4 @@ export default { | 参数 | 说明 | 类型 | 默认值 | 可选值 | |-----------|-----------|-----------|-------------|-------------| -| value | 利用`v-model`绑定当前组件是否显示 | Boolean | '' | | \ No newline at end of file +| value | 利用`v-model`绑定当前组件是否显示 | Boolean | '' | | diff --git a/docs/nav.config.json b/docs/nav.config.json index 38c9aee7c..6046705d1 100644 --- a/docs/nav.config.json +++ b/docs/nav.config.json @@ -80,6 +80,10 @@ "path": "/popup", "title": "Popup" }, + { + "path": "/dialog", + "title": "Dialog" + }, { "path": "/swipe", "title": "Swipe" diff --git a/packages/dialog/CHANGELOG.md b/packages/dialog/CHANGELOG.md new file mode 100644 index 000000000..e88c472b3 --- /dev/null +++ b/packages/dialog/CHANGELOG.md @@ -0,0 +1,8 @@ +## 0.0.2 (2017-01-20) + +* 改了bug A +* 加了功能B + +## 0.0.1 (2017-01-10) + +* 第一版 diff --git a/packages/dialog/README.md b/packages/dialog/README.md new file mode 100644 index 000000000..4c6172563 --- /dev/null +++ b/packages/dialog/README.md @@ -0,0 +1,26 @@ +# @youzan/<%= name %> + +!!! 请在此处填写你的文档最简单描述 !!! + +[![version][version-image]][download-url] +[![download][download-image]][download-url] + +[version-image]: http://npm.qima-inc.com/badge/v/@youzan/<%= name %>.svg?style=flat-square +[download-image]: http://npm.qima-inc.com/badge/d/@youzan/<%= name %>.svg?style=flat-square +[download-url]: http://npm.qima-inc.com/package/@youzan/<%= name %> + +## Demo + +## Usage + +## API + +| 参数 | 说明 | 类型 | 默认值 | 可选值 | +|-----------|-----------|-----------|-------------|-------------| +| className | 自定义额外类名 | string | '' | '' | + + + + +## License +[MIT](https://opensource.org/licenses/MIT) diff --git a/packages/dialog/index.js b/packages/dialog/index.js new file mode 100644 index 000000000..cb8dcd8d5 --- /dev/null +++ b/packages/dialog/index.js @@ -0,0 +1,3 @@ +import Dialog from './src/dialog.js'; + +export default Dialog; diff --git a/packages/dialog/package.json b/packages/dialog/package.json new file mode 100644 index 000000000..7dbfa2900 --- /dev/null +++ b/packages/dialog/package.json @@ -0,0 +1,10 @@ +{ + "name": "<%= name %>", + "version": "<%= version %>", + "description": "<%= description %>", + "main": "./lib/index.js", + "author": "<%= author %>", + "license": "<%= license %>", + "devDependencies": {}, + "dependencies": {} +} diff --git a/packages/dialog/src/dialog.js b/packages/dialog/src/dialog.js new file mode 100644 index 000000000..bb08501b8 --- /dev/null +++ b/packages/dialog/src/dialog.js @@ -0,0 +1,98 @@ +import Vue from 'vue'; +import Dialog from './dialog.vue'; +import merge from 'src/utils/merge'; + +const DialogConstructor = Vue.extend(Dialog); + +let currentDialog; +let instance; +let dialogQueue = []; + +const defaultCallback = action => { + if (currentDialog) { + let callback = currentDialog.callback; + + if (typeof callback === 'function') { + callback(action); + } + + if (currentDialog.resolve && action !== 'cancel') { + currentDialog.resolve(action); + } else { + currentDialog.reject(action); + } + } +}; + +var initInstance = () => { + instance = new DialogConstructor({ + el: document.createElement('div') + }); + + instance.callback = defaultCallback; +}; + +var showNextDialog = () => { + if (!instance) { + initInstance(); + } + + if (!instance.value && dialogQueue.length > 0) { + currentDialog = dialogQueue.shift(); + + let options = currentDialog.options; + + for (let prop in options) { + if (options.hasOwnProperty(prop)) { + instance[prop] = options[prop]; + } + } + console.log(instance) + + if (options.callback === undefined) { + instance.callback = defaultCallback; + } + + document.body.appendChild(instance.$el); + + Vue.nextTick(() => { + instance.value = true; + }); + } +}; + +var DialogBox = options => { + console.log(options) + return new Promise((resolve, reject) => { // eslint-disable-line + dialogQueue.push({ + options: merge({}, options), + callback: options.callback, + resolve: resolve, + reject: reject + }); + + showNextDialog(); + }); +}; + +DialogBox.alert = function(options) { + return DialogBox(merge({ + type: 'alert', + closeOnClickOverlay: false + }, options)); +}; + +DialogBox.confirm = function(options) { + return DialogBox(merge({ + type: 'confirm', + showCancelButton: true + }, options)); +}; + +DialogBox.close = function() { + instance.value = false; + dialogQueue = []; + currentDialog = null; +}; + +export default DialogBox; diff --git a/packages/dialog/src/dialog.vue b/packages/dialog/src/dialog.vue new file mode 100644 index 000000000..62a1124c4 --- /dev/null +++ b/packages/dialog/src/dialog.vue @@ -0,0 +1,63 @@ + + + diff --git a/packages/zanui/src/dialog.pcss b/packages/zanui/src/dialog.pcss new file mode 100644 index 000000000..c6b2b4d48 --- /dev/null +++ b/packages/zanui/src/dialog.pcss @@ -0,0 +1,87 @@ +@import "./mixins/border_retina.pcss"; + +@component-namespace o2 { + @component dialog-wrapper { + position: absolute; + } + + @component dialog { + position: fixed; + top: 50%; + left: 50%; + transform: translate3d(-50%, -50%, 0); + background-color: #fff; + width: 85%; + border-radius: 4px; + font-size: 16px; + overflow: hidden; + backface-visibility: hidden; + transition: .2s; + + @descendent header { + padding: 15px 0 0; + } + + @descendent content { + padding: 10px 20px 15px; + min-height: 36px; + position: relative; + + &::after { + @mixin border-retina (bottom); + } + } + + @descendent title { + text-align: center; + padding-left: 0; + margin-bottom: 0; + font-size: 16px; + color: #333; + } + + @descendent message { + color: #999; + margin: 0; + text-align: center; + font-size: 14px; + line-height: 36px; + } + + @descendent footer { + font-size: 14px; + overflow: hidden; + } + + .is-twobtn { + .o2-dialog-btn { + width: 50%; + } + + .o2-dialog-cancel { + &::after { + @mixin border-retina (right); + } + } + } + + @descendent btn { + line-height: 40px; + border: 0; + background-color: #fff; + float: left; + box-sizing: border-box; + text-align: center; + position: relative; + } + + @descendent cancel { + color: #333; + } + + @descendent confirm { + color: #00C000; + width: 100%; + } + } +} diff --git a/packages/zanui/src/index.pcss b/packages/zanui/src/index.pcss index 554cafe0f..64007adf1 100644 --- a/packages/zanui/src/index.pcss +++ b/packages/zanui/src/index.pcss @@ -3,6 +3,7 @@ */ @import './button.pcss'; @import './cell.pcss'; +@import './dialog.pcss'; @import './field.pcss'; @import './icon.pcss'; @import './popup.pcss'; diff --git a/src/index.js b/src/index.js index 42ea5ca67..b3dd83c70 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import Cell from '../packages/cell/index.js'; import Icon from '../packages/icon/index.js'; import CellGroup from '../packages/cell-group/index.js'; import Popup from '../packages/popup/index.js'; +import Dialog from '../packages/dialog/index.js'; // zanui import '../packages/zanui/src/index.pcss'; @@ -20,6 +21,7 @@ const install = function(Vue) { Vue.component(Icon.name, Icon); Vue.component(CellGroup.name, CellGroup); Vue.component(Popup.name, Popup); + // Vue.component(Dialog.name, Dialog); }; // auto install @@ -37,5 +39,6 @@ module.exports = { Cell, Icon, CellGroup, - Popup + Popup, + Dialog }; diff --git a/src/utils/merge.js b/src/utils/merge.js index c0aa39a55..564a989a4 100644 --- a/src/utils/merge.js +++ b/src/utils/merge.js @@ -1,6 +1,6 @@ export default function(target, ...sources) { - for (let i = 1, j = sources.length; i < j; i++) { - let source = arguments[i] || {}; + for (let i = 0; i < sources.length; i++) { + let source = sources[i] || {}; for (let prop in source) { if (source.hasOwnProperty(prop)) { let value = source[prop]; From 7b0ab582d733dfdf4890fc67e8533d6f7396ba93 Mon Sep 17 00:00:00 2001 From: cookfront Date: Thu, 16 Feb 2017 15:30:50 +0800 Subject: [PATCH 3/8] dialog component --- docs/examples/dialog.md | 6 ++++++ packages/dialog/src/dialog.js | 10 +++++----- packages/dialog/src/dialog.vue | 26 +++++++++++++++++++++++++- packages/zanui/src/dialog.pcss | 9 +++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/docs/examples/dialog.md b/docs/examples/dialog.md index 05fa69801..7863a1488 100644 --- a/docs/examples/dialog.md +++ b/docs/examples/dialog.md @@ -7,6 +7,8 @@ export default { Dialog.alert({ title: 'alert', message: 'alert message' + }).then((action) => { + console.log(action); }); }, @@ -14,6 +16,10 @@ export default { Dialog.confirm({ title: 'confirm', message: 'confirm message' + }).then((action) => { + console.log(action); + }, (error) => { + console.log(error); }); } } diff --git a/packages/dialog/src/dialog.js b/packages/dialog/src/dialog.js index bb08501b8..0a3ff9623 100644 --- a/packages/dialog/src/dialog.js +++ b/packages/dialog/src/dialog.js @@ -16,9 +16,9 @@ const defaultCallback = action => { callback(action); } - if (currentDialog.resolve && action !== 'cancel') { + if (currentDialog.resolve && action === 'confirm') { currentDialog.resolve(action); - } else { + } else if (currentDialog.reject && action === 'cancel') { currentDialog.reject(action); } } @@ -47,7 +47,6 @@ var showNextDialog = () => { instance[prop] = options[prop]; } } - console.log(instance) if (options.callback === undefined) { instance.callback = defaultCallback; @@ -62,7 +61,6 @@ var showNextDialog = () => { }; var DialogBox = options => { - console.log(options) return new Promise((resolve, reject) => { // eslint-disable-line dialogQueue.push({ options: merge({}, options), @@ -78,13 +76,15 @@ var DialogBox = options => { DialogBox.alert = function(options) { return DialogBox(merge({ type: 'alert', - closeOnClickOverlay: false + closeOnClickOverlay: false, + showCancelButton: false }, options)); }; DialogBox.confirm = function(options) { return DialogBox(merge({ type: 'confirm', + closeOnClickOverlay: true, showCancelButton: true }, options)); }; diff --git a/packages/dialog/src/dialog.vue b/packages/dialog/src/dialog.vue index 62a1124c4..f68e29ced 100644 --- a/packages/dialog/src/dialog.vue +++ b/packages/dialog/src/dialog.vue @@ -1,5 +1,5 @@