UNPKG

s94-web

Version:

常用的web工具方法封装---牧人与鱼

249 lines (239 loc) 8.61 kB
var s94_web = require('s94-web'); var s94_pjax = (function (global){ let document = global?.document; if (!document) return console.error('缺少 document 对象!'); var cache_prefix = 's94-pjax_'; /** * 当pjax出错的时候,刷新页面 */ function onerror(){ window.location.reload() } /** * 绑定的元素的click事件的回调函数 * @param {Event} e event */ function onclick(e){ if(this.getAttribute('target') == '_blank') return false; if(pjax(this.getAttribute('href'), e)){ e.preventDefault(); e.stopPropagation(); } } /** * 锚点跳转 * @param {String} id 跳转的ID */ function anchorJump(id){ var dom; if(id && (dom = document.querySelector(id)) ){ s94_web.screenOffsetPage(s94_web.domOffsetPage(dom)); }else{ s94_web.screenOffsetPage(0); } } /** * 异步请求跳转的页面内容,并按请求的url缓存(便于在popstate中获取) * @param {String} url 请求跳转地址 */ function pjax_ajax(url, callback){ s94_web.ajax({ global: false, url: url, success: function(res){ if(!res || typeof(res)!="string") return onerror(); //ajax返回的数据不是String,直接跳出 s94_web.cache(cache_prefix+url, res); //把获取的res按请求的url缓存,便于在popstate中获取 typeof(callback)=='function' && callback(res); }, error: onerror, }); } /** * 根据数据,渲染容器(pjax.container)里面的内容 */ function display(){ function appendjs(arr, i){ if(i >= arr.length)return; if (arr[i].src) { return s94_web.loadJs({src:arr[i].src, refresh:true, parent:arr[i].parent, type: arr[i].type}, function(){appendjs(arr, i+1)}); } else{ var js = document.createElement('script'); js.text = arr[i].innerHTML; js.type = arr[i].type; arr[i].parent.appendChild(js); appendjs(arr, i+1); } } var outer = document.querySelector(pjax.container), scripts=[], fullHtml=false, content='', title=''; if(!outer) return onerror(); //当前页面不存在容器,直接跳出 //内容解析 pjax.html.replace(/<title[^>]*>([\s\S.]*)<\/title>/i,function(m,p1){ title = p1;return ''; }) if (fullHtml = pjax.html.match(/<html[^>]*>([\s\S.]*)<\/html>/i)) { var htmlDom = document.createElement('html'); htmlDom.innerHTML = fullHtml[1]; var contentDom = htmlDom.querySelector(pjax.container); if(!contentDom) return onerror(); //需要渲染的内容里面,没有容器元素,直接跳出 content = contentDom.innerHTML; }else{ content = pjax.html; } //容器内容清理 outer.innerHTML = ''; //内容渲染 document.title = title; s94_web(content).each(function(row){ outer.appendChild(row); }) scripts = s94_web(outer).find('script').each(function(){ this.parent = this.parentNode; }).remove(); appendjs(scripts, 0); //渲染完成后续工作 anchorJump(window.location.href.replace(/^[^\#]+/,'')); //锚点跳转定位 pjax.on(); //绑定渲染内容部分没有绑定pjax的部分元素 s94_web(window).trigger('pjax:display'); //广播pjax:display事件 } /** * 修改state * @param {Object} data 修改的数据 */ function replaceState(data){ var state = window.history.state || {}; state = s94_web.merge(state, data); window.history.replaceState(state, ""); } /** * 初始化,在pjax.init中调用,页面刷新之前只运行一次。主要用于绑定popstate事件和定义 */ function init(){ if(init.inited) return; init.inited = true; //绑定popstate事件 window.addEventListener('popstate', function(e){ if(!e.state || !e.state.container){ //可能是a标签默认的锚点跳转 replaceState({container:pjax.container, selector_arr:pjax.selector_arr}); }else{ s94_web(window).trigger('pjax:popstate'); //广播pjax:display事件 var state = e.state; pjax.container = state.container; pjax.selector_arr = state.selector_arr; var url = window.location.href.replace(/\#.*$/,'') pjax.html = s94_web.cache(cache_prefix+url); //从缓存中获取页面数据 if(pjax.html){ display(); }else{ pjax_ajax(url, function(res){ pjax.html = res; display(); }) } } }) } /* ---------------------------------- 以上为私有方法 ---------------------------- */ /** * 主方法,无刷新页面跳转 * @param {String} href 跳转地址 * @param {*} e 事件对象 */ function pjax(href, e){ e = e || window.event || {}; if(!pjax.container || !document.querySelector(pjax.container)) return false;//缺少pjax容器的,跳转失败 if(!href || /^javascript/.test(href)) return false; //地址为空或者以javascript开头的,跳转失败 var to = s94_web.url(href); var local = s94_web.url(window.location.href); if(to.origin != local.origin) return false; //地址和当前location不同源的,跳转失败 if(to.href == local.href) return false; //地址和当前location相同,跳转失败 //插入历史记录(假跳转) window.history.pushState({container:pjax.container, selector_arr:pjax.selector_arr}, "", to.href); var to_url = to.href.replace(/\#.*$/,''); if(local.href.replace(/\#.*$/,'') == to_url) { //仅仅hash部分不同,不对页面重新渲染,只进行锚点跳转 anchorJump(to.hash); }else{ //ajax获取跳转地址内容,然后重新渲染容器内容 s94_web(window).trigger('pjax:before', e); pjax_ajax(to_url, function(res){ s94_web(window).trigger('pjax:success', e); //广播pjax:success事件 pjax.html = res; display(); }) } return true; } pjax.selector_arr = []; //用于存放pjax.on注册的selector /** * pjax初始化,用于指定容器(指定容器的时候,会修改state)。第一次初始化会额外绑定popstate事件 * @param {String} container 容器的选择器字符串 */ pjax.init = function(container){ if(!container || typeof(container)!="string") throw Error('容器参数错误'); pjax.container = container; //修改state replaceState({container:pjax.container}); init(); //初始化操作(在当前页面确定pjax容器后执行) return pjax; } /** * 绑定指定元素,使他们点击后执行pjax * @param {String} selector 用于指定元素的选择器字符串 */ pjax.on = function(selector){ if(!pjax.container) return pjax; if(typeof(selector)=="undefined"){ for (var i = 0; i < pjax.selector_arr.length; i++) { s94_web(pjax.selector_arr[i]).each(function(){ if (this.lock_pjax) return; this.lock_pjax = true; this.addEventListener('click', onclick, false); //绑定渲染内容部分没有绑定pjax的部分元素 }) } }else if(selector){ if(pjax.selector_arr.indexOf(selector)==-1) { pjax.selector_arr.push(selector); replaceState({selector_arr: pjax.selector_arr}); //修改state中的selector_arr,便于popstate中渲染内容后绑定 } s94_web(selector).each(function(){ if (this.lock_pjax) return; this.lock_pjax = true; this.addEventListener('click', onclick, false); }) } return pjax; } /** * 解绑指定或所有元素 * @param {String} selector 用于指定元素的选择器字符串,必须和pjax.on传入的selector相同 */ pjax.off = function(selector){ if(!pjax.container) return pjax; if(typeof(selector)!="undefined"){ for (var i = 0; i < pjax.selector_arr.length; i++) { s94_web(pjax.selector_arr[i]).each(function(){ if (!this.lock_pjax) return; this.lock_pjax = undefined; this.removeEventListener('click', onclick); }) } pjax.selector_arr = []; replaceState({selector_arr: pjax.selector_arr}); }else{ var index = pjax.selector_arr.indexOf(selector); if(index == -1) return pjax; pjax.selector_arr.splice(index, 1); replaceState({selector_arr: pjax.selector_arr}); s94_web(selector).each(function(){ if (!this.lock_pjax) return; this.lock_pjax = undefined; this.removeEventListener('click', onclick); }) } return pjax; } return pjax; })(typeof globalThis !== 'undefined' ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}); if (typeof exports === 'object' && typeof module === 'object'){ //CommonJS module.exports = s94_pjax; }