index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. function ownKeys(object, enumerableOnly) {
  4. var keys = Object.keys(object);
  5. if (Object.getOwnPropertySymbols) {
  6. var symbols = Object.getOwnPropertySymbols(object);
  7. if (enumerableOnly) symbols = symbols.filter(function (sym) {
  8. return Object.getOwnPropertyDescriptor(object, sym).enumerable;
  9. });
  10. keys.push.apply(keys, symbols);
  11. }
  12. return keys;
  13. }
  14. function _objectSpread(target) {
  15. for (var i = 1; i < arguments.length; i++) {
  16. var source = arguments[i] != null ? arguments[i] : {};
  17. if (i % 2) {
  18. ownKeys(source, true).forEach(function (key) {
  19. _defineProperty(target, key, source[key]);
  20. });
  21. } else if (Object.getOwnPropertyDescriptors) {
  22. Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
  23. } else {
  24. ownKeys(source).forEach(function (key) {
  25. Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
  26. });
  27. }
  28. }
  29. return target;
  30. }
  31. function _defineProperty(obj, key, value) {
  32. if (key in obj) {
  33. Object.defineProperty(obj, key, {
  34. value: value,
  35. enumerable: true,
  36. configurable: true,
  37. writable: true
  38. });
  39. } else {
  40. obj[key] = value;
  41. }
  42. return obj;
  43. }
  44. function _typeof(obj) {
  45. if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
  46. _typeof = function _typeof(obj) {
  47. return typeof obj;
  48. };
  49. } else {
  50. _typeof = function _typeof(obj) {
  51. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  52. };
  53. }
  54. return _typeof(obj);
  55. }
  56. var RE_NUM = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source;
  57. function getClientPosition(elem) {
  58. var box;
  59. var x;
  60. var y;
  61. var doc = elem.ownerDocument;
  62. var body = doc.body;
  63. var docElem = doc && doc.documentElement; // 根据 GBS 最新数据,A-Grade Browsers 都已支持 getBoundingClientRect 方法,不用再考虑传统的实现方式
  64. box = elem.getBoundingClientRect(); // 注:jQuery 还考虑减去 docElem.clientLeft/clientTop
  65. // 但测试发现,这样反而会导致当 html 和 body 有边距/边框样式时,获取的值不正确
  66. // 此外,ie6 会忽略 html 的 margin 值,幸运地是没有谁会去设置 html 的 margin
  67. x = box.left;
  68. y = box.top; // In IE, most of the time, 2 extra pixels are added to the top and left
  69. // due to the implicit 2-pixel inset border. In IE6/7 quirks mode and
  70. // IE6 standards mode, this border can be overridden by setting the
  71. // document element's border to zero -- thus, we cannot rely on the
  72. // offset always being 2 pixels.
  73. // In quirks mode, the offset can be determined by querying the body's
  74. // clientLeft/clientTop, but in standards mode, it is found by querying
  75. // the document element's clientLeft/clientTop. Since we already called
  76. // getClientBoundingRect we have already forced a reflow, so it is not
  77. // too expensive just to query them all.
  78. // ie 下应该减去窗口的边框吧,毕竟默认 absolute 都是相对窗口定位的
  79. // 窗口边框标准是设 documentElement ,quirks 时设置 body
  80. // 最好禁止在 body 和 html 上边框 ,但 ie < 9 html 默认有 2px ,减去
  81. // 但是非 ie 不可能设置窗口边框,body html 也不是窗口 ,ie 可以通过 html,body 设置
  82. // 标准 ie 下 docElem.clientTop 就是 border-top
  83. // ie7 html 即窗口边框改变不了。永远为 2
  84. // 但标准 firefox/chrome/ie9 下 docElem.clientTop 是窗口边框,即使设了 border-top 也为 0
  85. x -= docElem.clientLeft || body.clientLeft || 0;
  86. y -= docElem.clientTop || body.clientTop || 0;
  87. return {
  88. left: x,
  89. top: y
  90. };
  91. }
  92. function getScroll(w, top) {
  93. var ret = w["page".concat(top ? 'Y' : 'X', "Offset")];
  94. var method = "scroll".concat(top ? 'Top' : 'Left');
  95. if (typeof ret !== 'number') {
  96. var d = w.document; // ie6,7,8 standard mode
  97. ret = d.documentElement[method];
  98. if (typeof ret !== 'number') {
  99. // quirks mode
  100. ret = d.body[method];
  101. }
  102. }
  103. return ret;
  104. }
  105. function getScrollLeft(w) {
  106. return getScroll(w);
  107. }
  108. function getScrollTop(w) {
  109. return getScroll(w, true);
  110. }
  111. function getOffset(el) {
  112. var pos = getClientPosition(el);
  113. var doc = el.ownerDocument;
  114. var w = doc.defaultView || doc.parentWindow;
  115. pos.left += getScrollLeft(w);
  116. pos.top += getScrollTop(w);
  117. return pos;
  118. }
  119. function _getComputedStyle(elem, name, computedStyle_) {
  120. var val = '';
  121. var d = elem.ownerDocument;
  122. var computedStyle = computedStyle_ || d.defaultView.getComputedStyle(elem, null); // https://github.com/kissyteam/kissy/issues/61
  123. if (computedStyle) {
  124. val = computedStyle.getPropertyValue(name) || computedStyle[name];
  125. }
  126. return val;
  127. }
  128. var _RE_NUM_NO_PX = new RegExp("^(".concat(RE_NUM, ")(?!px)[a-z%]+$"), 'i');
  129. var RE_POS = /^(top|right|bottom|left)$/;
  130. var CURRENT_STYLE = 'currentStyle';
  131. var RUNTIME_STYLE = 'runtimeStyle';
  132. var LEFT = 'left';
  133. var PX = 'px';
  134. function _getComputedStyleIE(elem, name) {
  135. // currentStyle maybe null
  136. // http://msdn.microsoft.com/en-us/library/ms535231.aspx
  137. var ret = elem[CURRENT_STYLE] && elem[CURRENT_STYLE][name]; // 当 width/height 设置为百分比时,通过 pixelLeft 方式转换的 width/height 值
  138. // 一开始就处理了! CUSTOM_STYLE.height,CUSTOM_STYLE.width ,cssHook 解决@2011-08-19
  139. // 在 ie 下不对,需要直接用 offset 方式
  140. // borderWidth 等值也有问题,但考虑到 borderWidth 设为百分比的概率很小,这里就不考虑了
  141. // From the awesome hack by Dean Edwards
  142. // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  143. // If we're not dealing with a regular pixel number
  144. // but a number that has a weird ending, we need to convert it to pixels
  145. // exclude left right for relativity
  146. if (_RE_NUM_NO_PX.test(ret) && !RE_POS.test(name)) {
  147. // Remember the original values
  148. var style = elem.style;
  149. var left = style[LEFT];
  150. var rsLeft = elem[RUNTIME_STYLE][LEFT]; // prevent flashing of content
  151. elem[RUNTIME_STYLE][LEFT] = elem[CURRENT_STYLE][LEFT]; // Put in the new values to get a computed value out
  152. style[LEFT] = name === 'fontSize' ? '1em' : ret || 0;
  153. ret = style.pixelLeft + PX; // Revert the changed values
  154. style[LEFT] = left;
  155. elem[RUNTIME_STYLE][LEFT] = rsLeft;
  156. }
  157. return ret === '' ? 'auto' : ret;
  158. }
  159. var getComputedStyleX;
  160. if (typeof window !== 'undefined') {
  161. getComputedStyleX = window.getComputedStyle ? _getComputedStyle : _getComputedStyleIE;
  162. }
  163. function each(arr, fn) {
  164. for (var i = 0; i < arr.length; i++) {
  165. fn(arr[i]);
  166. }
  167. }
  168. function isBorderBoxFn(elem) {
  169. return getComputedStyleX(elem, 'boxSizing') === 'border-box';
  170. }
  171. var BOX_MODELS = ['margin', 'border', 'padding'];
  172. var CONTENT_INDEX = -1;
  173. var PADDING_INDEX = 2;
  174. var BORDER_INDEX = 1;
  175. var MARGIN_INDEX = 0;
  176. function swap(elem, options, callback) {
  177. var old = {};
  178. var style = elem.style;
  179. var name; // Remember the old values, and insert the new ones
  180. for (name in options) {
  181. if (options.hasOwnProperty(name)) {
  182. old[name] = style[name];
  183. style[name] = options[name];
  184. }
  185. }
  186. callback.call(elem); // Revert the old values
  187. for (name in options) {
  188. if (options.hasOwnProperty(name)) {
  189. style[name] = old[name];
  190. }
  191. }
  192. }
  193. function getPBMWidth(elem, props, which) {
  194. var value = 0;
  195. var prop;
  196. var j;
  197. var i;
  198. for (j = 0; j < props.length; j++) {
  199. prop = props[j];
  200. if (prop) {
  201. for (i = 0; i < which.length; i++) {
  202. var cssProp = void 0;
  203. if (prop === 'border') {
  204. cssProp = "".concat(prop + which[i], "Width");
  205. } else {
  206. cssProp = prop + which[i];
  207. }
  208. value += parseFloat(getComputedStyleX(elem, cssProp)) || 0;
  209. }
  210. }
  211. }
  212. return value;
  213. }
  214. /**
  215. * A crude way of determining if an object is a window
  216. * @member util
  217. */
  218. function isWindow(obj) {
  219. // must use == for ie8
  220. /* eslint eqeqeq:0 */
  221. return obj != null && obj == obj.window;
  222. }
  223. var domUtils = {};
  224. each(['Width', 'Height'], function (name) {
  225. domUtils["doc".concat(name)] = function (refWin) {
  226. var d = refWin.document;
  227. return Math.max( // firefox chrome documentElement.scrollHeight< body.scrollHeight
  228. // ie standard mode : documentElement.scrollHeight> body.scrollHeight
  229. d.documentElement["scroll".concat(name)], // quirks : documentElement.scrollHeight 最大等于可视窗口多一点?
  230. d.body["scroll".concat(name)], domUtils["viewport".concat(name)](d));
  231. };
  232. domUtils["viewport".concat(name)] = function (win) {
  233. // pc browser includes scrollbar in window.innerWidth
  234. var prop = "client".concat(name);
  235. var doc = win.document;
  236. var body = doc.body;
  237. var documentElement = doc.documentElement;
  238. var documentElementProp = documentElement[prop]; // 标准模式取 documentElement
  239. // backcompat 取 body
  240. return doc.compatMode === 'CSS1Compat' && documentElementProp || body && body[prop] || documentElementProp;
  241. };
  242. });
  243. /*
  244. 得到元素的大小信息
  245. @param elem
  246. @param name
  247. @param {String} [extra] 'padding' : (css width) + padding
  248. 'border' : (css width) + padding + border
  249. 'margin' : (css width) + padding + border + margin
  250. */
  251. function getWH(elem, name, extra) {
  252. if (isWindow(elem)) {
  253. return name === 'width' ? domUtils.viewportWidth(elem) : domUtils.viewportHeight(elem);
  254. } else if (elem.nodeType === 9) {
  255. return name === 'width' ? domUtils.docWidth(elem) : domUtils.docHeight(elem);
  256. }
  257. var which = name === 'width' ? ['Left', 'Right'] : ['Top', 'Bottom'];
  258. var borderBoxValue = name === 'width' ? elem.offsetWidth : elem.offsetHeight;
  259. var computedStyle = getComputedStyleX(elem);
  260. var isBorderBox = isBorderBoxFn(elem);
  261. var cssBoxValue = 0;
  262. if (borderBoxValue == null || borderBoxValue <= 0) {
  263. borderBoxValue = undefined; // Fall back to computed then un computed css if necessary
  264. cssBoxValue = getComputedStyleX(elem, name);
  265. if (cssBoxValue == null || Number(cssBoxValue) < 0) {
  266. cssBoxValue = elem.style[name] || 0;
  267. } // Normalize '', auto, and prepare for extra
  268. cssBoxValue = parseFloat(cssBoxValue) || 0;
  269. }
  270. if (extra === undefined) {
  271. extra = isBorderBox ? BORDER_INDEX : CONTENT_INDEX;
  272. }
  273. var borderBoxValueOrIsBorderBox = borderBoxValue !== undefined || isBorderBox;
  274. var val = borderBoxValue || cssBoxValue;
  275. if (extra === CONTENT_INDEX) {
  276. if (borderBoxValueOrIsBorderBox) {
  277. return val - getPBMWidth(elem, ['border', 'padding'], which);
  278. }
  279. return cssBoxValue;
  280. }
  281. if (borderBoxValueOrIsBorderBox) {
  282. var padding = extra === PADDING_INDEX ? -getPBMWidth(elem, ['border'], which) : getPBMWidth(elem, ['margin'], which);
  283. return val + (extra === BORDER_INDEX ? 0 : padding);
  284. }
  285. return cssBoxValue + getPBMWidth(elem, BOX_MODELS.slice(extra), which);
  286. }
  287. var cssShow = {
  288. position: 'absolute',
  289. visibility: 'hidden',
  290. display: 'block'
  291. }; // fix #119 : https://github.com/kissyteam/kissy/issues/119
  292. function getWHIgnoreDisplay(elem) {
  293. var val;
  294. var args = arguments; // in case elem is window
  295. // elem.offsetWidth === undefined
  296. if (elem.offsetWidth !== 0) {
  297. val = getWH.apply(undefined, args);
  298. } else {
  299. swap(elem, cssShow, function () {
  300. val = getWH.apply(undefined, args);
  301. });
  302. }
  303. return val;
  304. }
  305. function css(el, name, v) {
  306. var value = v;
  307. if (_typeof(name) === 'object') {
  308. for (var i in name) {
  309. if (name.hasOwnProperty(i)) {
  310. css(el, i, name[i]);
  311. }
  312. }
  313. return undefined;
  314. }
  315. if (typeof value !== 'undefined') {
  316. if (typeof value === 'number') {
  317. value += 'px';
  318. }
  319. el.style[name] = value;
  320. return undefined;
  321. }
  322. return getComputedStyleX(el, name);
  323. }
  324. each(['width', 'height'], function (name) {
  325. var first = name.charAt(0).toUpperCase() + name.slice(1);
  326. domUtils["outer".concat(first)] = function (el, includeMargin) {
  327. return el && getWHIgnoreDisplay(el, name, includeMargin ? MARGIN_INDEX : BORDER_INDEX);
  328. };
  329. var which = name === 'width' ? ['Left', 'Right'] : ['Top', 'Bottom'];
  330. domUtils[name] = function (elem, val) {
  331. if (val !== undefined) {
  332. if (elem) {
  333. var computedStyle = getComputedStyleX(elem);
  334. var isBorderBox = isBorderBoxFn(elem);
  335. if (isBorderBox) {
  336. val += getPBMWidth(elem, ['padding', 'border'], which);
  337. }
  338. return css(elem, name, val);
  339. }
  340. return undefined;
  341. }
  342. return elem && getWHIgnoreDisplay(elem, name, CONTENT_INDEX);
  343. };
  344. }); // 设置 elem 相对 elem.ownerDocument 的坐标
  345. function setOffset(elem, offset) {
  346. // set position first, in-case top/left are set even on static elem
  347. if (css(elem, 'position') === 'static') {
  348. elem.style.position = 'relative';
  349. }
  350. var old = getOffset(elem);
  351. var ret = {};
  352. var current;
  353. var key;
  354. for (key in offset) {
  355. if (offset.hasOwnProperty(key)) {
  356. current = parseFloat(css(elem, key)) || 0;
  357. ret[key] = current + offset[key] - old[key];
  358. }
  359. }
  360. css(elem, ret);
  361. }
  362. var util = _objectSpread({
  363. getWindow: function getWindow(node) {
  364. var doc = node.ownerDocument || node;
  365. return doc.defaultView || doc.parentWindow;
  366. },
  367. offset: function offset(el, value) {
  368. if (typeof value !== 'undefined') {
  369. setOffset(el, value);
  370. } else {
  371. return getOffset(el);
  372. }
  373. },
  374. isWindow: isWindow,
  375. each: each,
  376. css: css,
  377. clone: function clone(obj) {
  378. var ret = {};
  379. for (var i in obj) {
  380. if (obj.hasOwnProperty(i)) {
  381. ret[i] = obj[i];
  382. }
  383. }
  384. var overflow = obj.overflow;
  385. if (overflow) {
  386. for (var _i in obj) {
  387. if (obj.hasOwnProperty(_i)) {
  388. ret.overflow[_i] = obj.overflow[_i];
  389. }
  390. }
  391. }
  392. return ret;
  393. },
  394. scrollLeft: function scrollLeft(w, v) {
  395. if (isWindow(w)) {
  396. if (v === undefined) {
  397. return getScrollLeft(w);
  398. }
  399. window.scrollTo(v, getScrollTop(w));
  400. } else {
  401. if (v === undefined) {
  402. return w.scrollLeft;
  403. }
  404. w.scrollLeft = v;
  405. }
  406. },
  407. scrollTop: function scrollTop(w, v) {
  408. if (isWindow(w)) {
  409. if (v === undefined) {
  410. return getScrollTop(w);
  411. }
  412. window.scrollTo(getScrollLeft(w), v);
  413. } else {
  414. if (v === undefined) {
  415. return w.scrollTop;
  416. }
  417. w.scrollTop = v;
  418. }
  419. },
  420. viewportWidth: 0,
  421. viewportHeight: 0
  422. }, domUtils);
  423. function scrollIntoView(elem, container, config) {
  424. config = config || {}; // document 归一化到 window
  425. if (container.nodeType === 9) {
  426. container = util.getWindow(container);
  427. }
  428. var allowHorizontalScroll = config.allowHorizontalScroll;
  429. var onlyScrollIfNeeded = config.onlyScrollIfNeeded;
  430. var alignWithTop = config.alignWithTop;
  431. var alignWithLeft = config.alignWithLeft;
  432. var offsetTop = config.offsetTop || 0;
  433. var offsetLeft = config.offsetLeft || 0;
  434. var offsetBottom = config.offsetBottom || 0;
  435. var offsetRight = config.offsetRight || 0;
  436. allowHorizontalScroll = allowHorizontalScroll === undefined ? true : allowHorizontalScroll;
  437. var isWin = util.isWindow(container);
  438. var elemOffset = util.offset(elem);
  439. var eh = util.outerHeight(elem);
  440. var ew = util.outerWidth(elem);
  441. var containerOffset;
  442. var ch;
  443. var cw;
  444. var containerScroll;
  445. var diffTop;
  446. var diffBottom;
  447. var win;
  448. var winScroll;
  449. var ww;
  450. var wh;
  451. if (isWin) {
  452. win = container;
  453. wh = util.height(win);
  454. ww = util.width(win);
  455. winScroll = {
  456. left: util.scrollLeft(win),
  457. top: util.scrollTop(win)
  458. }; // elem 相对 container 可视视窗的距离
  459. diffTop = {
  460. left: elemOffset.left - winScroll.left - offsetLeft,
  461. top: elemOffset.top - winScroll.top - offsetTop
  462. };
  463. diffBottom = {
  464. left: elemOffset.left + ew - (winScroll.left + ww) + offsetRight,
  465. top: elemOffset.top + eh - (winScroll.top + wh) + offsetBottom
  466. };
  467. containerScroll = winScroll;
  468. } else {
  469. containerOffset = util.offset(container);
  470. ch = container.clientHeight;
  471. cw = container.clientWidth;
  472. containerScroll = {
  473. left: container.scrollLeft,
  474. top: container.scrollTop
  475. }; // elem 相对 container 可视视窗的距离
  476. // 注意边框, offset 是边框到根节点
  477. diffTop = {
  478. left: elemOffset.left - (containerOffset.left + (parseFloat(util.css(container, 'borderLeftWidth')) || 0)) - offsetLeft,
  479. top: elemOffset.top - (containerOffset.top + (parseFloat(util.css(container, 'borderTopWidth')) || 0)) - offsetTop
  480. };
  481. diffBottom = {
  482. left: elemOffset.left + ew - (containerOffset.left + cw + (parseFloat(util.css(container, 'borderRightWidth')) || 0)) + offsetRight,
  483. top: elemOffset.top + eh - (containerOffset.top + ch + (parseFloat(util.css(container, 'borderBottomWidth')) || 0)) + offsetBottom
  484. };
  485. }
  486. if (diffTop.top < 0 || diffBottom.top > 0) {
  487. // 强制向上
  488. if (alignWithTop === true) {
  489. util.scrollTop(container, containerScroll.top + diffTop.top);
  490. } else if (alignWithTop === false) {
  491. util.scrollTop(container, containerScroll.top + diffBottom.top);
  492. } else {
  493. // 自动调整
  494. if (diffTop.top < 0) {
  495. util.scrollTop(container, containerScroll.top + diffTop.top);
  496. } else {
  497. util.scrollTop(container, containerScroll.top + diffBottom.top);
  498. }
  499. }
  500. } else {
  501. if (!onlyScrollIfNeeded) {
  502. alignWithTop = alignWithTop === undefined ? true : !!alignWithTop;
  503. if (alignWithTop) {
  504. util.scrollTop(container, containerScroll.top + diffTop.top);
  505. } else {
  506. util.scrollTop(container, containerScroll.top + diffBottom.top);
  507. }
  508. }
  509. }
  510. if (allowHorizontalScroll) {
  511. if (diffTop.left < 0 || diffBottom.left > 0) {
  512. // 强制向上
  513. if (alignWithLeft === true) {
  514. util.scrollLeft(container, containerScroll.left + diffTop.left);
  515. } else if (alignWithLeft === false) {
  516. util.scrollLeft(container, containerScroll.left + diffBottom.left);
  517. } else {
  518. // 自动调整
  519. if (diffTop.left < 0) {
  520. util.scrollLeft(container, containerScroll.left + diffTop.left);
  521. } else {
  522. util.scrollLeft(container, containerScroll.left + diffBottom.left);
  523. }
  524. }
  525. } else {
  526. if (!onlyScrollIfNeeded) {
  527. alignWithLeft = alignWithLeft === undefined ? true : !!alignWithLeft;
  528. if (alignWithLeft) {
  529. util.scrollLeft(container, containerScroll.left + diffTop.left);
  530. } else {
  531. util.scrollLeft(container, containerScroll.left + diffBottom.left);
  532. }
  533. }
  534. }
  535. }
  536. }
  537. exports.default = scrollIntoView;
  538. //# sourceMappingURL=index.js.map