diff --git a/package.json b/package.json index 96f88a71b49d6508e25e20bdb440105d3818392a..4167ea8709e2e2b9190b4d9fba5554e8d221da1a 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,13 @@ "lint": "eslint --fix --config package.json --ext .js --ext .vue --ignore-path .eslintignore build src", "dev:h5": "npm run lint && cross-env NODE_ENV=production UNI_WATCH=true UNI_PLATFORM=h5 node build/build.js", "build:h5": "npm run lint && cross-env NODE_ENV=production UNI_WATCH=false UNI_PLATFORM=h5 node build/build.js", - "build:app-plus": "cross-env UNI_PLATFORM=app-plus rollup -c build/rollup.config.js", - "build:service:legacy": "npm run lint && rollup -c build/rollup.config.service.js", + "build:app-plus": "cross-env UNI_PLATFORM=app-plus rollup -c build/rollup.config.js", + "build:service:legacy": "npm run lint && rollup -c build/rollup.config.service.js", "build:mp-qq": "cross-env UNI_PLATFORM=mp-qq rollup -c build/rollup.config.js", "build:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin rollup -c build/rollup.config.js", "build:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu rollup -c build/rollup.config.js", "build:mp-alipay": "cross-env UNI_PLATFORM=mp-alipay rollup -c build/rollup.config.js", - "build:mp-toutiao": "cross-env UNI_PLATFORM=mp-toutiao rollup -c build/rollup.config.js", + "build:mp-toutiao": "cross-env UNI_PLATFORM=mp-toutiao rollup -c build/rollup.config.js", "build:runtime": "npm run lint && npm run build:mp-weixin && npm run build:mp-qq && npm run build:mp-alipay && npm run build:mp-baidu && npm run build:mp-toutiao && npm run build:app-plus", "test:unit": "cross-env NODE_ENV=test UNI_PLATFORM=h5 mocha-webpack --require tests/unit/setup.js --webpack-config build/webpack.config.test.js tests/unit/**/*.spec.js" }, @@ -38,6 +38,7 @@ "eslint-plugin-promise": "^4.0.0", "eslint-plugin-standard": "^4.0.0", "eslint-plugin-vue": "^4.7.1", + "intersection-observer": "^0.7.0", "jsdom": "^13.0.0", "jsdom-global": "^3.0.2", "rollup": "^0.67.4", diff --git a/src/core/service/api/create-intersection-observer.js b/src/core/service/api/create-intersection-observer.js new file mode 100644 index 0000000000000000000000000000000000000000..474c8747e65c50a5814c5100645e32f7ef2924be --- /dev/null +++ b/src/core/service/api/create-intersection-observer.js @@ -0,0 +1,83 @@ +import Vue from 'vue' +import 'intersection-observer' + +const defaultOptions = { + thresholds: [0], + initialRatio: 0, + observeAll: false +} + +class MPIntersectionObserver { + _intersectionObserver + _el + _options + _root = null + _rootMargin = '0' + constructor (context, options) { + this._el = context.$el + this._options = Object.assign({}, defaultOptions, options) + } + _makeRootMargin (margins = {}) { + this._rootMargin = ['top', 'right', 'bottom', 'left'].map(name => `${Number(margins[name]) || 0}px`).join(' ') + } + relativeTo (selector, margins) { + this._root = this._el.querySelector(selector) + this._makeRootMargin(margins) + } + relativeToViewport (margins) { + this._root = null + this._makeRootMargin(margins) + } + observe (selector, callback) { + if (typeof callback !== 'function') { + return + } + let options = { + root: this._root, + rootMargin: this._rootMargin, + threshold: this._options.thresholds + } + let intersectionObserver = this._intersectionObserver = new IntersectionObserver((entries, observer) => { + entries.forEach(entrie => { + callback({ + intersectionRatio: entrie.intersectionRatio, + intersectionRect: entrie.intersectionRect, + boundingClientRect: entrie.boundingClientRect, + relativeRect: entrie.rootBounds, + time: entrie.time, + dataset: entrie.target.dataset, + id: entrie.target.id + }) + }) + }, options) + if (this._options.observeAll) { + intersectionObserver.USE_MUTATION_OBSERVER = true + Array.prototype.map.call(this._el.querySelectorAll(selector), el => { + intersectionObserver.observe(el) + }) + } else { + intersectionObserver.USE_MUTATION_OBSERVER = false + intersectionObserver.observe(this._el.querySelector(selector)) + } + } + disconnect () { + this._intersectionObserver && this._intersectionObserver.disconnect() + } +} + +export function createIntersectionObserver (context, options) { + if (!(context instanceof Vue)) { + options = context + context = null + } + if (context) { + return new MPIntersectionObserver(context, options) + } + const pages = getCurrentPages() + if (pages.length) { + context = pages[pages.length - 1] + return new MPIntersectionObserver(context, options) + } else { + UniServiceJSBridge.emit('onError', 'createIntersectionObserver:fail') + } +} diff --git a/src/platforms/h5/helpers/todo-api.js b/src/platforms/h5/helpers/todo-api.js index a6c021b18eeaa839e4518959402ac1858bba4ec1..1bdb9d792a0033cdfb66fc228134484c788a23fe 100644 --- a/src/platforms/h5/helpers/todo-api.js +++ b/src/platforms/h5/helpers/todo-api.js @@ -49,7 +49,6 @@ export default [ 'setBackgroundTextStyle', 'createAnimation', 'loadFontFace', - 'createIntersectionObserver', 'getProvider', 'login', 'checkSession', diff --git a/yarn.lock b/yarn.lock index 43057fec4d604c6bc1228ebaa5730fae9f3c2077..ba98094d31f71bdf2f40dd2b06ce0a7331650eac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3977,6 +3977,10 @@ interpret@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" +intersection-observer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.7.0.tgz#ee16bee978db53516ead2f0a8154b09b400bbdc9" + invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"