UNPKG

hm-react-cli

Version:

Create a Huimei React project by module

172 lines (153 loc) 4.98 kB
import { getWindow } from 'react-core/util'; //计划有history hash iframe三种模式 export var modeObject = {}; //伪造一个Location对象 function getLocation(source) { const location = { getPath() { return modeObject.value === 'hash' ? this.hash.slice(1) : this.pathname; }, state: source.history.state, key: (source.history.state && source.history.state.key) || 'initial' }; for (const key in source.location) { if (Object.prototype.hasOwnProperty.call(source.location, key)) { location[key] = source.location[key]; } } return location; } //伪造一个History对象 function createHistory(source) { let listeners = []; let transitioning = false; let resolveTransition = () => {}; let target = { //减少魔法,提高兼容性,将只读的访问器属性改成普通属性 location: getLocation(source), transitioning, _onTransitionComplete() { target.transitioning = transitioning = false; resolveTransition(); }, listen(listener) { listeners.push(listener); let popstateListener = e => { target.location = getLocation(source); listener(); }; var event = modeObject.value === 'hash' ? 'hashchange' : 'popstate'; addEvent(source, event, popstateListener); return () => { removeEvent(source, event, popstateListener); listeners = listeners.filter(fn => fn !== listener); }; }, navigate(to, { state, replace = false } = {}) { state = { ...state, key: Date.now() + '' }; // try...catch iOS Safari limits to 100 pushState calls var slocation = source.location; if (modeObject.value === 'hash') { if (replace && slocation.hash !== newHash) { history.back(); } slocation.hash = to; } else { try { if (transitioning || replace) { source.history.replaceState(state, null, to); } else { source.history.pushState(state, null, to); } } catch (e) { slocation[replace ? 'replace' : 'assign'](to); } } target.location = getLocation(source); target.transitioning = transitioning = true; let transition = new Promise(res => (resolveTransition = res)); listeners.forEach(fn => fn()); return transition; } }; return target; } function addEvent(dom, name, fn) { if (dom.addEventListener) { dom.addEventListener(name, fn); } else if (dom.attachEvent) { dom.attachEvent('on' + name, fn); } } function removeEvent(dom, name, fn) { if (dom.removeEventListener) { dom.removeEventListener(name, fn); } else if (dom.detachEvent) { dom.detachEvent('on' + name, fn); } } //////////////////////////////////////////////////////////////////////////////// // 伪造一个window对象 function createMemorySource(initialPathname = '/') { let index = 0; let states = []; let stack = [ { pathname: initialPathname, search: '' } ]; let target = { // location addEventListener(name, fn) {}, removeEventListener(name, fn) {}, history: { // index // entries, // state back() {}, pushState(state, _, uri) { index++; stack.push(uri2obj(uri)); states.push(state); sync(target); }, replaceState(state, _, uri) { stack[index] = uri2obj(uri); states[index] = state; sync(target); } } }; function sync(target) { var history = target.history; history.index = index; history.entries = stack; history.state = states[index]; target.location = stack[index]; } sync(target); return target; } function uri2obj(uri) { let arr = uri.split('?'); let pathname = arr[0]; let search = arr[1] || ''; return { pathname, search }; } //////////////////////////////////////////////////////////////////////////////// // global history - uses window.history as the source if available, otherwise a // memory history let win = getWindow(); let getSource = () => { return win.location ? win : createMemorySource(); }; let globalHistory = createHistory(getSource()); let { navigate } = globalHistory; export { globalHistory, navigate, createHistory, createMemorySource };