* [html5] fix appear events when components's v-if is false, & fix appear events in update hooks.
Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/ca4f1997 Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/ca4f1997 Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/ca4f1997 Branch: refs/heads/0.12-dev Commit: ca4f1997d2ff0677dd942b88724cd9095d06948e Parents: b040496 Author: MrRaindrop <tekk...@gmail.com> Authored: Thu Apr 13 17:37:11 2017 +0800 Committer: MrRaindrop <tekk...@gmail.com> Committed: Thu Apr 13 17:37:11 2017 +0800 ---------------------------------------------------------------------- .eslintrc | 3 +- .gitignore | 1 + build/webpack.test.web.config.js | 2 +- html5/render/vue/mixins/base.js | 1 + html5/render/vue/utils/component.js | 83 +-- html5/render/vue/utils/event.js | 32 +- .../vue/data/build/dotvue/scoped-style.js | 525 ------------------- .../vue/data/dotvue/first-screen-appear.vue | 21 + html5/test/render/vue/data/dotvue/foo.vue | 27 + html5/test/render/vue/helper/main.js | 80 +++ html5/test/render/vue/helper/mixin/done.js | 9 + html5/test/render/vue/helper/mixin/index.js | 1 + html5/test/render/vue/helper/runtime.js | 40 +- html5/test/render/vue/utils/component.js | 38 ++ 14 files changed, 253 insertions(+), 610 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/.eslintrc ---------------------------------------------------------------------- diff --git a/.eslintrc b/.eslintrc index f3d34fd..75c1fc2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -33,7 +33,8 @@ "notifyTrimMemory": false, "markupState": false, "compileAndRunBundle": false, - "expect": false + "expect": false, + "sinon": false }, "rules": { http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index 50e9ce3..334fdb8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ examples/build web-entry test/build +data/build weex_tmp coverage dist http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/build/webpack.test.web.config.js ---------------------------------------------------------------------- diff --git a/build/webpack.test.web.config.js b/build/webpack.test.web.config.js index 6b55480..7357d0f 100644 --- a/build/webpack.test.web.config.js +++ b/build/webpack.test.web.config.js @@ -26,7 +26,7 @@ function walk(dir) { // var entryFile = path.join(entryDirectory, path.basename(file, extname) + '.js'); // fs.outputFileSync(entryFile, getEntryFileContent(entryFile, fullpath)); var name = path.join('html5/test/render/vue/data', 'build', dir, path.basename(file, extname)); - entry[name] = fullpath + entry[name] = [fullpath] } else if (stat.isDirectory() && file !== 'build' && file !== 'include') { var subdir = path.join(dir, file); walk(subdir); http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/render/vue/mixins/base.js ---------------------------------------------------------------------- diff --git a/html5/render/vue/mixins/base.js b/html5/render/vue/mixins/base.js index c13fb91..0bfd2ad 100644 --- a/html5/render/vue/mixins/base.js +++ b/html5/render/vue/mixins/base.js @@ -67,6 +67,7 @@ export default { if (process.env.NODE_ENV === 'development') { tagUpdated() } + watchAppear(this) }, methods: { http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/render/vue/utils/component.js ---------------------------------------------------------------------- diff --git a/html5/render/vue/utils/component.js b/html5/render/vue/utils/component.js index 0bd07b8..989499e 100644 --- a/html5/render/vue/utils/component.js +++ b/html5/render/vue/utils/component.js @@ -33,11 +33,12 @@ export function hasIntersection (rect, ctRect) { } /** - * [isElementVisible description] + * isElementVisible * @param {HTMLElement} el a dom element. * @param {HTMLElement} container optional, the container of this el. */ export function isElementVisible (el, container) { + if (!el.getBoundingClientRect) { return false } const bodyRect = { top: 0, left: 0, @@ -68,10 +69,23 @@ export function isComponentVisible (component) { return false } -// TODO: improve the efficiency -export function watchAppear (context) { - if (!context) return null +// to trigger the appear/disappear event. +function triggerEvent (elm, handlers, isShow, dir) { + const evt = isShow ? 'appear' : 'disappear' + let listener = handlers[evt] + if (listener && listener.fn) { + listener = listener.fn + } + if (listener) { + listener(createEvent(elm, evt, { + direction: dir + })) + } +} +export function watchAppear (context) { + if (!context || !context.$el) return null + const el = context.$el context.$nextTick(() => { if ((context.$options && context.$options._parentListeners) || (context.$vnode && context.$vnode.data && context.$vnode.data.on)) { @@ -86,42 +100,37 @@ export function watchAppear (context) { else { isWindow = true } - let lastScrollTop = container.scrollTop || window.pageYOffset - - context._visible = isElementVisible(context.$el, isWindow ? document.body : container) - if (context._visible && on.appear) { - if (on.appear.fn) { - on.appear = on.appear.fn - } - on.appear(createEvent(context.$el, 'appear', { direction: null })) + const visible = isElementVisible(el, isWindow ? document.body : container) + context._visible = visible + // if the component hasn't appeared for once yet, then it shouldn't trigger + // a disappear event at all. + if (context._appearedOnce) { + triggerEvent(el, on, visible, null) } - const handler = throttle(event => { - const visible = isElementVisible(context.$el, isWindow ? document.body : container) - let listener = null - let type = null - if (visible !== context._visible) { - context._visible = visible - if (visible) { - listener = on.appear - type = 'appear' - } - else { - listener = on.disappear - type = 'disappear' - } - if (listener && listener.fn) { - listener = listener.fn + else if (visible) { + context._appearedOnce = true + triggerEvent(el, on, true, null) + } + + let lastScrollTop = container.scrollTop || window.pageYOffset + // no need to watch the same vComponent again. + if (!context._scrollWatched) { + context._scrollWatched = true + const handler = throttle(event => { + const visible = isElementVisible(el, isWindow ? document.body : container) + if (visible !== context._visible) { + context._visible = visible + const scrollTop = container.scrollTop || window.pageYOffset + const dir = scrollTop < lastScrollTop + ? 'down' : scrollTop > lastScrollTop + ? 'up' : null + triggerEvent(el, on, visible, dir) + lastScrollTop = scrollTop } - const scrollTop = container.scrollTop || window.pageYOffset - listener && listener(createEvent(context.$el, type, { - direction: scrollTop < lastScrollTop ? 'down' - : scrollTop > lastScrollTop ? 'up' : null - })) - lastScrollTop = scrollTop - } - }, 25, true) + }, 25, true) - container.addEventListener('scroll', handler, false) + container.addEventListener('scroll', handler, false) + } } } }) http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/render/vue/utils/event.js ---------------------------------------------------------------------- diff --git a/html5/render/vue/utils/event.js b/html5/render/vue/utils/event.js index f518bfc..ac84c87 100644 --- a/html5/render/vue/utils/event.js +++ b/html5/render/vue/utils/event.js @@ -33,17 +33,22 @@ function extend (to, ...args) { * @param {DOMString} type * @param {Object} props */ -export function createEvent (context, type, props) { +export function createEvent (target, type, props) { const event = new Event(type, { bubbles: false }) // event.preventDefault() // event.stopPropagation() extend(event, props) - Object.defineProperty(event, 'target', { - enumerable: true, - value: context || null - }) + try { + Object.defineProperty(event, 'target', { + enumerable: true, + value: target || null + }) + } + catch (err) { + return extend({}, event, { target: target || null }) + } return event } @@ -53,7 +58,7 @@ export function createEvent (context, type, props) { * @param {DOMString} type * @param {Object} props */ -export function createCustomEvent (context, type, props) { +export function createCustomEvent (target, type, props) { // compatibility: http://caniuse.com/#search=customevent // const event = new CustomEvent(type) const event = document.createEvent('CustomEvent') @@ -63,11 +68,16 @@ export function createCustomEvent (context, type, props) { extend(event, props) - // TODO: event.target is readonly - Object.defineProperty(event, 'target', { - enumerable: true, - value: context || null - }) + // event.target is readonly + try { + Object.defineProperty(event, 'target', { + enumerable: true, + value: target || null + }) + } + catch (err) { + return extend({}, event, { target: target || null }) + } return event } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/data/build/dotvue/scoped-style.js ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/data/build/dotvue/scoped-style.js b/html5/test/render/vue/data/build/dotvue/scoped-style.js deleted file mode 100644 index b87ba8a..0000000 --- a/html5/test/render/vue/data/build/dotvue/scoped-style.js +++ /dev/null @@ -1,525 +0,0 @@ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else { - var a = factory(); - for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; - } -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - - /* styles */ - __webpack_require__(1) - - var Component = __webpack_require__(6)( - /* script */ - null, - /* template */ - __webpack_require__(7), - /* scopeId */ - "data-v-0776c87b", - /* cssModules */ - null - ) - Component.options.__file = "/Users/rdp/www/rdp/github/MrRaindrop/weex/html5/test/render/vue/data/dotvue/scoped-style.vue" - if (Component.esModule && Object.keys(Component.esModule).some(function (key) {return key !== "default" && key !== "__esModule"})) {console.error("named exports are not supported in *.vue files.")} - if (Component.options.functional) {console.error("[vue-loader] scoped-style.vue: functional components are not supported with templates, they should use render functions.")} - - /* hot reload */ - if (false) {(function () { - var hotAPI = require("vue-loader/node_modules/vue-hot-reload-api") - hotAPI.install(require("vue"), false) - if (!hotAPI.compatible) return - module.hot.accept() - if (!module.hot.data) { - hotAPI.createRecord("data-v-0776c87b", Component.options) - } else { - hotAPI.reload("data-v-0776c87b", Component.options) - } - })()} - - module.exports = Component.exports - - -/***/ }, -/* 1 */ -/***/ function(module, exports, __webpack_require__) { - - // style-loader: Adds some css to the DOM by adding a <style> tag - - // load the styles - var content = __webpack_require__(2); - if(typeof content === 'string') content = [[module.id, content, '']]; - if(content.locals) module.exports = content.locals; - // add the styles to the DOM - var update = __webpack_require__(4)("27230129", content, false); - // Hot Module Replacement - if(false) { - // When the styles change, update the <style> tags - if(!content.locals) { - module.hot.accept("!!../../../../../../node_modules/.0.26.1@css-loader/index.js!../../../../../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-0776c87b\",\"scoped\":true,\"hasInlineConfig\":false}!../../../../../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./scoped-style.vue", function() { - var newContent = require("!!../../../../../../node_modules/.0.26.1@css-loader/index.js!../../../../../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-0776c87b\",\"scoped\":true,\"hasInlineConfig\":false}!../../../../../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./scoped-style.vue"); - if(typeof newContent === 'string') newContent = [[module.id, newContent, '']]; - update(newContent); - }); - } - // When the module is disposed, remove the <style> tags - module.hot.dispose(function() { update(); }); - } - -/***/ }, -/* 2 */ -/***/ function(module, exports, __webpack_require__) { - - exports = module.exports = __webpack_require__(3)(); - // imports - - - // module - exports.push([module.id, "\n.ct[data-v-0776c87b] {\n width: 200px;\n flex-direction: row;\n transform: translate3d(100px, 100px, 0);\n}\n", ""]); - - // exports - - -/***/ }, -/* 3 */ -/***/ function(module, exports) { - - /* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra - */ - // css base code, injected by the css-loader - module.exports = function() { - var list = []; - - // return the list of modules as css string - list.toString = function toString() { - var result = []; - for(var i = 0; i < this.length; i++) { - var item = this[i]; - if(item[2]) { - result.push("@media " + item[2] + "{" + item[1] + "}"); - } else { - result.push(item[1]); - } - } - return result.join(""); - }; - - // import a list of modules into the list - list.i = function(modules, mediaQuery) { - if(typeof modules === "string") - modules = [[null, modules, ""]]; - var alreadyImportedModules = {}; - for(var i = 0; i < this.length; i++) { - var id = this[i][0]; - if(typeof id === "number") - alreadyImportedModules[id] = true; - } - for(i = 0; i < modules.length; i++) { - var item = modules[i]; - // skip already imported module - // this implementation is not 100% perfect for weird media query combinations - // when a module is imported multiple times with different media queries. - // I hope this will never occur (Hey this way we have smaller bundles) - if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { - if(mediaQuery && !item[2]) { - item[2] = mediaQuery; - } else if(mediaQuery) { - item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; - } - list.push(item); - } - } - }; - return list; - }; - - -/***/ }, -/* 4 */ -/***/ function(module, exports, __webpack_require__) { - - /* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra - Modified by Evan You @yyx990803 - */ - - var hasDocument = typeof document !== 'undefined' - - if (false) { - if (!hasDocument) { - throw new Error( - 'vue-style-loader cannot be used in a non-browser environment. ' + - "Use { target: 'node' } in your Webpack config to indicate a server-rendering environment." - ) } - } - - var listToStyles = __webpack_require__(5) - - /* - type StyleObject = { - id: number; - parts: Array<StyleObjectPart> - } - - type StyleObjectPart = { - css: string; - media: string; - sourceMap: ?string - } - */ - - var stylesInDom = {/* - [id: number]: { - id: number, - refs: number, - parts: Array<(obj?: StyleObjectPart) => void> - } - */} - - var head = hasDocument && (document.head || document.getElementsByTagName('head')[0]) - var singletonElement = null - var singletonCounter = 0 - var isProduction = false - var noop = function () {} - - // Force single-tag solution on IE6-9, which has a hard limit on the # of <style> - // tags it will allow on a page - var isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\b/.test(navigator.userAgent.toLowerCase()) - - module.exports = function (parentId, list, _isProduction) { - isProduction = _isProduction - - var styles = listToStyles(parentId, list) - addStylesToDom(styles) - - return function update (newList) { - var mayRemove = [] - for (var i = 0; i < styles.length; i++) { - var item = styles[i] - var domStyle = stylesInDom[item.id] - domStyle.refs-- - mayRemove.push(domStyle) - } - if (newList) { - styles = listToStyles(parentId, newList) - addStylesToDom(styles) - } else { - styles = [] - } - for (var i = 0; i < mayRemove.length; i++) { - var domStyle = mayRemove[i] - if (domStyle.refs === 0) { - for (var j = 0; j < domStyle.parts.length; j++) { - domStyle.parts[j]() - } - delete stylesInDom[domStyle.id] - } - } - } - } - - function addStylesToDom (styles /* Array<StyleObject> */) { - for (var i = 0; i < styles.length; i++) { - var item = styles[i] - var domStyle = stylesInDom[item.id] - if (domStyle) { - domStyle.refs++ - for (var j = 0; j < domStyle.parts.length; j++) { - domStyle.parts[j](item.parts[j]) - } - for (; j < item.parts.length; j++) { - domStyle.parts.push(addStyle(item.parts[j])) - } - if (domStyle.parts.length > item.parts.length) { - domStyle.parts.length = item.parts.length - } - } else { - var parts = [] - for (var j = 0; j < item.parts.length; j++) { - parts.push(addStyle(item.parts[j])) - } - stylesInDom[item.id] = { id: item.id, refs: 1, parts: parts } - } - } - } - - function createStyleElement () { - var styleElement = document.createElement('style') - styleElement.type = 'text/css' - head.appendChild(styleElement) - return styleElement - } - - function addStyle (obj /* StyleObjectPart */) { - var update, remove - var styleElement = document.querySelector('style[data-vue-ssr-id~="' + obj.id + '"]') - - if (styleElement) { - if (isProduction) { - // has SSR styles and in production mode. - // simply do nothing. - return noop - } else { - // has SSR styles but in dev mode. - // for some reason Chrome can't handle source map in server-rendered - // style tags - source maps in <style> only works if the style tag is - // created and inserted dynamically. So we remove the server rendered - // styles and inject new ones. - styleElement.parentNode.removeChild(styleElement) - } - } - - if (isOldIE) { - // use singleton mode for IE9. - var styleIndex = singletonCounter++ - styleElement = singletonElement || (singletonElement = createStyleElement()) - update = applyToSingletonTag.bind(null, styleElement, styleIndex, false) - remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true) - } else { - // use multi-style-tag mode in all other cases - styleElement = createStyleElement() - update = applyToTag.bind(null, styleElement) - remove = function () { - styleElement.parentNode.removeChild(styleElement) - } - } - - update(obj) - - return function updateStyle (newObj /* StyleObjectPart */) { - if (newObj) { - if (newObj.css === obj.css && - newObj.media === obj.media && - newObj.sourceMap === obj.sourceMap) { - return - } - update(obj = newObj) - } else { - remove() - } - } - } - - var replaceText = (function () { - var textStore = [] - - return function (index, replacement) { - textStore[index] = replacement - return textStore.filter(Boolean).join('\n') - } - })() - - function applyToSingletonTag (styleElement, index, remove, obj) { - var css = remove ? '' : obj.css - - if (styleElement.styleSheet) { - styleElement.styleSheet.cssText = replaceText(index, css) - } else { - var cssNode = document.createTextNode(css) - var childNodes = styleElement.childNodes - if (childNodes[index]) styleElement.removeChild(childNodes[index]) - if (childNodes.length) { - styleElement.insertBefore(cssNode, childNodes[index]) - } else { - styleElement.appendChild(cssNode) - } - } - } - - function applyToTag (styleElement, obj) { - var css = obj.css - var media = obj.media - var sourceMap = obj.sourceMap - - if (media) { - styleElement.setAttribute('media', media) - } - - if (sourceMap) { - // https://developer.chrome.com/devtools/docs/javascript-debugging - // this makes source maps inside style tags work properly in Chrome - css += '\n/*# sourceURL=' + sourceMap.sources[0] + ' */' - // http://stackoverflow.com/a/26603875 - css += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + ' */' - } - - if (styleElement.styleSheet) { - styleElement.styleSheet.cssText = css - } else { - while (styleElement.firstChild) { - styleElement.removeChild(styleElement.firstChild) - } - styleElement.appendChild(document.createTextNode(css)) - } - } - - -/***/ }, -/* 5 */ -/***/ function(module, exports) { - - /** - * Translates the list format produced by css-loader into something - * easier to manipulate. - */ - module.exports = function listToStyles (parentId, list) { - var styles = [] - var newStyles = {} - for (var i = 0; i < list.length; i++) { - var item = list[i] - var id = item[0] - var css = item[1] - var media = item[2] - var sourceMap = item[3] - var part = { - id: parentId + ':' + i, - css: css, - media: media, - sourceMap: sourceMap - } - if (!newStyles[id]) { - styles.push(newStyles[id] = { id: id, parts: [part] }) - } else { - newStyles[id].parts.push(part) - } - } - return styles - } - - -/***/ }, -/* 6 */ -/***/ function(module, exports) { - - // this module is a runtime utility for cleaner component module output and will - // be included in the final webpack user bundle - - module.exports = function normalizeComponent ( - rawScriptExports, - compiledTemplate, - scopeId, - cssModules - ) { - var esModule - var scriptExports = rawScriptExports = rawScriptExports || {} - - // ES6 modules interop - var type = typeof rawScriptExports.default - if (type === 'object' || type === 'function') { - esModule = rawScriptExports - scriptExports = rawScriptExports.default - } - - // Vue.extend constructor export interop - var options = typeof scriptExports === 'function' - ? scriptExports.options - : scriptExports - - // render functions - if (compiledTemplate) { - options.render = compiledTemplate.render - options.staticRenderFns = compiledTemplate.staticRenderFns - } - - // scopedId - if (scopeId) { - options._scopeId = scopeId - } - - // inject cssModules - if (cssModules) { - var computed = Object.create(options.computed || null) - Object.keys(cssModules).forEach(function (key) { - var module = cssModules[key] - computed[key] = function () { return module } - }) - options.computed = computed - } - - return { - esModule: esModule, - exports: scriptExports, - options: options - } - } - - -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h; - return _c('div', [_c('div', { - ref: "foo", - staticClass: "ct", - staticStyle: { - "height": "200px" - }, - style: ({ - backgroundColor: 'red' - }) - })]) - },staticRenderFns: []} - module.exports.render._withStripped = true - if (false) { - module.hot.accept() - if (module.hot.data) { - require("vue-loader/node_modules/vue-hot-reload-api").rerender("data-v-0776c87b", module.exports) - } - } - -/***/ } -/******/ ]) -}); -; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/data/dotvue/first-screen-appear.vue ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/data/dotvue/first-screen-appear.vue b/html5/test/render/vue/data/dotvue/first-screen-appear.vue new file mode 100644 index 0000000..c2fe877 --- /dev/null +++ b/html5/test/render/vue/data/dotvue/first-screen-appear.vue @@ -0,0 +1,21 @@ +<template> + <div> + <foo @appear="appear" @disappear="disappear"></foo> + </div> +</template> + +<script> + module.exports = { + components: { + foo: require('./foo.vue') + }, + methods: { + appear: function (evt) { + window._spy_first_screen_appear(evt) + }, + disappear: function (evt) { + window._spy_first_screen_appear(evt) + } + } + } +</script> http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/data/dotvue/foo.vue ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/data/dotvue/foo.vue b/html5/test/render/vue/data/dotvue/foo.vue new file mode 100644 index 0000000..57d8591 --- /dev/null +++ b/html5/test/render/vue/data/dotvue/foo.vue @@ -0,0 +1,27 @@ +<template> + <div v-if="show" style="width:200px;height:200px;background-color:red;"></div> +</template> + +<script> +module.exports = { + data () { + return { + show: false + } + }, + mounted () { + setTimeout(() => { + this.show = true + setTimeout(() => { + this.show = false + setTimeout(() => { + this.show = true + setTimeout(() => { + this.done('test-first-screen-appear') + }, 25) + }, 300) + }, 300) + }, 300) + } +} +</script> http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/helper/main.js ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/helper/main.js b/html5/test/render/vue/helper/main.js new file mode 100644 index 0000000..962e078 --- /dev/null +++ b/html5/test/render/vue/helper/main.js @@ -0,0 +1,80 @@ +import weex from '../../../../render/vue/env/weex' +import * as utils from './utils' + +const helper = { + roots: {}, + _done: {}, + + utils, + /** + * register a component. + * @param {string} name, + * @param {object} component. + */ + register (name, component) { + weex.registerComponent(name, component) + // components[name] = component + }, + + /** + * create a vm instance of Vue. + * @param {Object} options. + * @return {Vue} vue instance. + */ + createVm (options = {}, id) { + // options.components = components + let ct, root + const Vue = weex.__vue__ + if (id) { + ct = document.createElement('div') + ct.id = `${id}-root` + ct.style.cssText = 'width:100%;height:300px;overflow:scroll;' + root = document.createElement('div') + root.id = id + ct.appendChild(root) + document.body.appendChild(ct) + this.roots[id] = root + } + return new Vue(options).$mount(root) + }, + + clearAll () { + const roots = this.roots + Object.keys(roots).forEach((id) => { + const ct = roots[id].parentNode + document.body.removeChild(ct) + }) + this.roots = {} + }, + + clear (id) { + if (!id) { + return this.clearAll() + } + const roots = this.roots + const root = roots[id] + if (!root) { return } + const ct = roots[id].parentNode + document.body.removeChild(ct) + }, + + registerDone (id, cb) { + this._done[id] = cb + }, + + done (id, ...args) { + const done = this._done[id] + done && done(...args) + }, + + /** + * [compile description] + * @param {[type]} template [description] + * @return {[type]} [description] + */ + compile (template) { + return helper.createVm({ template }) + } +} + +export default helper http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/helper/mixin/done.js ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/helper/mixin/done.js b/html5/test/render/vue/helper/mixin/done.js new file mode 100644 index 0000000..d5a2b76 --- /dev/null +++ b/html5/test/render/vue/helper/mixin/done.js @@ -0,0 +1,9 @@ +import helper from '../main' + +export const doneMixin = { + methods: { + done (id, ...args) { + helper.done(id, ...args) + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/helper/mixin/index.js ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/helper/mixin/index.js b/html5/test/render/vue/helper/mixin/index.js new file mode 100644 index 0000000..9c34780 --- /dev/null +++ b/html5/test/render/vue/helper/mixin/index.js @@ -0,0 +1 @@ +export * from './done' http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/helper/runtime.js ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/helper/runtime.js b/html5/test/render/vue/helper/runtime.js index 522b132..09f3f01 100644 --- a/html5/test/render/vue/helper/runtime.js +++ b/html5/test/render/vue/helper/runtime.js @@ -6,8 +6,8 @@ import Vue from 'vue/dist/vue.runtime.esm.js' import { base, style } from '../../../../render/vue/mixins' import weex from '../../../../render/vue/env/weex' import { setVue } from '../../../../render/vue/env' - -import * as utils from './utils' +import helper from './main' +import { doneMixin } from './mixin' /** * Describe tests for current versions of Vue. @@ -24,6 +24,9 @@ export function init (title, fn) { Vue.mixin(base) Vue.mixin(style) + // for test only mixins. + Vue.mixin(doneMixin) + window.global = window global.weex = weex setVue(Vue) @@ -31,39 +34,6 @@ export function init (title, fn) { window._no_remove_style_sheets = true }) - const helper = { - - utils, - /** - * register a component. - * @param {string} name, - * @param {object} component. - */ - register (name, component) { - global.weex.registerComponent(name, component) - // components[name] = component - }, - - /** - * create a vm instance of Vue. - * @param {Object} options. - * @return {Vue} vue instance. - */ - createVm (options = {}) { - // options.components = components - return new Vue(options).$mount() - }, - - /** - * [compile description] - * @param {[type]} template [description] - * @return {[type]} [description] - */ - compile (template) { - return helper.createVm({ template }) - } - } - /** * describe a vue-render test for certain vue verson. */ http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/ca4f1997/html5/test/render/vue/utils/component.js ---------------------------------------------------------------------- diff --git a/html5/test/render/vue/utils/component.js b/html5/test/render/vue/utils/component.js new file mode 100644 index 0000000..06d7c70 --- /dev/null +++ b/html5/test/render/vue/utils/component.js @@ -0,0 +1,38 @@ +import { init } from '../helper/runtime' +import div from '../../../../render/vue/components/div' + +import firstScreenAppearBundle from '../data/build/dotvue/first-screen-appear.js' + +init('utils component', (Vue, helper) => { + const spys = { + 'appear': sinon.spy(), + 'disappear': sinon.spy() + } + window._spy_first_screen_appear = function (evt) { + const spy = spys[evt.type] + spy && spy(evt) + } + + before(() => { + helper.register('div', div) + }) + + describe('watchAppear', function () { + it('should work when mounted and updated.', function (done) { + const id = 'test-first-screen-appear' + helper.createVm(firstScreenAppearBundle, id) + helper.registerDone(id, () => { + const { appear: appearSpy, disappear: disappearSpy } = spys + expect(appearSpy.callCount).to.equal(2) + expect(disappearSpy.callCount).to.equal(1) + expect(appearSpy.args[0][0].type).to.equal('appear') + expect(appearSpy.args[1][0].type).to.equal('appear') + expect(disappearSpy.args[0][0].type).to.equal('disappear') + expect(appearSpy.args[0][0].direction).to.not.exist + expect(appearSpy.args[1][0].direction).to.not.exist + expect(disappearSpy.args[0][0].direction).to.not.exist + done() + }) + }) + }) +})