vis-pjax
v2.1.2
Published
通用pjax插件,轻量无依赖,开箱即用,支持过渡动画。
Downloads
312
Readme
Pjax
@visdoc/pjax是使用ts编写的一个pjax插件,独立单文件,无任何依赖,支持过渡动画,加载动画。
安装
npm install @visdoc/pjax
构造参数说明
- linkSelector
- 类型: string | (container: Element|Document) => Element|NodeList|null
- 描述: 连接元素选择器,支持字符串选择器,也可以是一个回调函数。回调函数可返回要监听事件的元素或null,参数container在初始化时为document对象,更新容器内容时为容器元素Element对象。
- 默认: 无
- containerSelectors
- 类型: string[]
- 描述: 需要替换的元素选择器,支持任意选择器,如:['.content','div.box','#container']
- 默认: 无
- options 可选配置
- options.debug
- 类型: boolean
- 描述: 是否开启调试模式,开启后请求加载页面失败,不会重定向
- 默认: false
- options.fetchOptions
- 类型: RequestInit
- 描述: fetch请求配置
- 默认: {method: 'GET',headers: {Accept: 'text/html'}
- options.behavior
- 类型: 'smooth' | 'auto' | 'instant'
- 描述: 页面滚动行为,默认为平滑滚动。用于滚动到锚点元素。
- 默认: 'smooth'
- options.topAnchors
- 类型: string|undefined
- 描述: 锚点元素,用于滚动到锚点元素id,无需添加#,如:top
- 默认:undefined 滚动到页面顶部
- options.eventDelegation
- 类型: boolean
- 描述: 允许事件委托,默认为true,如果为false,则只绑定当前元素,不处理子元素事件。
- 默认:true
- options.loadFailHandler
- 类型: 'redirect' | 'reload' | 'none'
- 描述: 页面加载失败时的,redirect重定向,reload强制刷新当前页面,none不处理。
- 默认: 'redirect' 重定向到加载失败的url。
- options.runInlineScript
- 类型: boolean
- 描述: 如果设置为true,则被替换的script标签中的内联脚本会被执行。
- 默认: false
- options.lock
- 类型: boolean
- 描述: 如果设置为true时,则加载过程中不会处理的新的click事件,直到加载完成。
- 默认: false
- options.cacheMaxLength
- 类型: number
- 描述: 缓存最大长度,默认为10,超过后,会删除最旧的缓存,0则不缓存。
- 默认: 10
- options.autoReplaceTitle
- 类型: boolean
- 描述: 自动替换页面标题,如果新文档存在title则替换。
- 默认: true
- options.logLevel
- 类型: boolean
- 描述: 日志等级,默认为全部日志,可选值有debug、info、warn、error
- 默认: ['debug','info','warn','error']
- options.debug
教程
- 基本使用
import Pjax from '@visdoc/pjax' // Pjax.isSupported() 判断是否支持window.history.pushState,不支持会使用window.location.href重定向页面 // 实例化 const pjax = new Pjax('a', ['#content']) // 等待初始化就绪 也是在等待页面dom渲染完成 await pjax.waitReadyState() // 更简洁的模式 await Pjax.create('a', ['#content'])
- 切换页面
// 基本使用 await Pjax.factory.loadPage('/page2.html') // 传入fetch请求头示范 await Pjax.factory.loadPage('/page2.html',{headers:{'token':'123'}})
- 绑定元素
// 一般情况下无需使用bindElement方法,除非动态添加了元素 // 注意:在创建pjax对象时传递的element会在页面切换过后自动重新绑定事件,也就是绑定一次就够了。 // bindElement方法绑定的元素不会在页面切换后重新绑定,需自行在beforeReplace钩子中进行重新绑定 // 某些动态渲染的元素,会导致事件失效,则可以用下面的方法重新绑定。 Pjax.factory.bindElement('a') // 解绑 Pjax.factory.unBindElement('a') // 为构造函数传入的选择器重新绑定事件 Pjax.factory.reset() // 指定父容器,只会重新绑定指定容下的元素 Pjax.factory.reset(document.querySelector('#container'))
- 🪝加载进度钩子
pjax.onProgress = (percentage,end) => { console.log('当前进度:'+percentage+'%,是否结束:'+end?'是':'否') }
- 🪝内容替换钩子
// oldElement类型为Element[],newElement类型为Element[]|string[] // 替换内容之前的钩子 pjax.beforeReplace = async (oldElement, newElement) => { // 添加 fade-out 类,开始淡出动画 oldElement.classList.add('fade-out'); // 等待动画结束 await new Promise(resolve => setTimeout(resolve, 500)); // 移除 fade-out 类,添加 fade-in 类,开始淡入动画 oldElement.classList.remove('fade-out'); } // 后置的钩子,此时内容已经替换完成 pjax.afterReplace = async (oldElement, newElement) => { oldElement.classList.add('fade-in'); // 等待动画结束 await new Promise(resolve => setTimeout(resolve, 500)); // 0.5秒的动画时间 // 移除 fade-in 类 oldElement.classList.remove('fade-in'); } // 自定义替换内容 pjax.beforeReplace = async (oldElement, newElement) => { // 没有从文档中获取到元素 if (newElement === null) newElement = '' // 替换元素 oldElement.innerHTML = typeof newElement === 'string' ? newElement : newElement.innerHTML return Promise.reject() // 返回Promise.reject()内部将不再执行默认的替换操作和afterReplace钩子 }
- 状态管理
// 强制刷新页面,等同于window.location.reload() Pjax.factory.reload(true) // 恢复到初始加载时的状态 Pjax.factory.reload(false) // 保存当前页面状态 Pjax.factory.saveState() // 获取页面状态 Pjax.factory.getState()
- 代理点击事件
document.getElementById('link') .addEventListener('click',function(e:Event){ // 执行自定义的逻辑.... // 把事件交给pjax处理 Pjax.factory.handleClickEvent.call(this,e) }) // 简洁写法 document.getElementById('link').addEventListener('click', Pjax.factory.handleClickEvent)
动画示例
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>进度条动画示例</title>
<style>
#progress-bar-container {
pointer-events: none; /*防止用户在动画期间与内容交互*/
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 1px;
z-index: 9999; /*确保进度条显示在所有内容之上*/
transform: translateY(-100%);
transition: transform .3s ease-in-out;
#progress-bar {
height: 100%;
width: 0;
transition: width 0.3s ease-in-out; /* 平滑过渡效果 */
background-color: #4caf50; /* 进度条颜色*/
}
}
</style>
</head>
<body>
<div id="progress-bar-container">
<div id="progress-bar"></div>
</div>
<div id="doc_content"></div>
<script type="module">
import Pjax from '@visdoc/pjax'
const pjax = new Pjax('#nav_container', ['#doc_content'], {
debug: true,
strictMatchClickEvent: false
})
// 等待初始化就绪
await pjax.waitReadyState()
// 进度条容器
const progressContainer = document.getElementById('progress-bar-container')
// 进度条元素
const progressBar = document.getElementById('progress-bar')
// 利用进度钩子显示进度条
pjax.onProgress = (progress, end) => {
if (progressBar) {
if (end) {
// 如果是结束,先将进度条宽度设置为100%
progressBar.style.width = '100%'
} else {
progressContainer.style.transform = 'translateY(0)'
// 更新进度条的宽度
progressBar.style.width = `${progress}%`
}
}
}
// 内容替换完成将进度条容器移动偏移出窗口
pjax.afterReplace = async (oldElement) => {
if (oldElement.id === 'doc_content') {
// 延迟500毫秒,关闭动画
await new Promise((resolve) => setTimeout(resolve, 500))
progressContainer.style.transform = 'translateY(-100%)'
}
}
// 模拟调用 onProgress
setTimeout(() => pjax.onProgress(30, false), 1000); // 1秒后进度为30%
setTimeout(() => pjax.onProgress(60, false), 2000); // 2秒后进度为60%
setTimeout(() => pjax.onProgress(100, true), 3000); // 3秒后进度为100%,并结束
</script>
</body>
</html>