index.js 18 KB

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