完成router-link跳转
parent
b068f90f0e
commit
34ac7ab8ed
|
@ -5,13 +5,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import { bind, fire } from 'wkit'
|
import { bind, fire } from 'wkit'
|
||||||
import { hideProp, targetIsThisWindow } from '../utils.js'
|
import { query2object } from '../utils.js'
|
||||||
|
|
||||||
//hash前缀正则
|
//hash前缀正则
|
||||||
const PREFIX_REGEXP = /^(#!|#)[\/]?/
|
const PREFIX_REGEXP = /^(#!|#)[\/]?/
|
||||||
const TRIM_REGEXP = /(^[/]+)|([/]+$)/g
|
const TRIM_REGEXP = /(^[/]+)|([/]+$)/g
|
||||||
const DEFAULT_OPTIONS = {
|
const DEFAULT_OPTIONS = {
|
||||||
prefix: '!/',
|
|
||||||
allowReload: true //连续点击同一个链接是否重新加载
|
allowReload: true //连续点击同一个链接是否重新加载
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,17 +47,12 @@ class Router {
|
||||||
this.#ready = true
|
this.#ready = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = location.hash
|
|
||||||
|
|
||||||
path = path.replace(PREFIX_REGEXP, '').trim()
|
|
||||||
path = path.replace(TRIM_REGEXP, '')
|
|
||||||
|
|
||||||
if (ev?.type === 'load') {
|
if (ev?.type === 'load') {
|
||||||
this.go(path)
|
// this.go()
|
||||||
// hash模式要手动触发一下路由检测
|
// hash模式要手动触发一下路由检测
|
||||||
this.#check(path)
|
this.#check()
|
||||||
} else {
|
} else {
|
||||||
this.#check(path)
|
this.#check()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,9 +94,18 @@ class Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 路由检测
|
// 路由检测
|
||||||
#check(path) {
|
#check() {
|
||||||
let { allowReload } = this.#options
|
let { allowReload } = this.#options
|
||||||
let $view = window.__wkitd__.get('ROUTER_VIEW')
|
let $view = window.__wkitd__.get('ROUTER_VIEW')
|
||||||
|
let path = location.hash
|
||||||
|
let query
|
||||||
|
|
||||||
|
if (path.includes('?')) {
|
||||||
|
;[path, query] = path.split('?')
|
||||||
|
}
|
||||||
|
path = path.replace(PREFIX_REGEXP, '').replace(TRIM_REGEXP, '')
|
||||||
|
|
||||||
|
// console.log(path, query, query2object(query))
|
||||||
|
|
||||||
if (!$view || (!allowReload && path === this.#route.path)) {
|
if (!$view || (!allowReload && path === this.#route.path)) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -3,128 +3,13 @@
|
||||||
* @author yutent<yutent.io@gmail.com>
|
* @author yutent<yutent.io@gmail.com>
|
||||||
* @date 2023/08/10 10:10:06
|
* @date 2023/08/10 10:10:06
|
||||||
*/
|
*/
|
||||||
|
import { Component } from 'wkit'
|
||||||
import { Component, html, raw } from 'wkit'
|
|
||||||
|
|
||||||
import createWebHashHistory from './hash-router.js'
|
import createWebHashHistory from './hash-router.js'
|
||||||
import createWebHistory from './modern-router.js'
|
import createWebHistory from './modern-router.js'
|
||||||
|
import './router-components.js'
|
||||||
|
|
||||||
export { createWebHashHistory, createWebHistory }
|
export { createWebHashHistory, createWebHistory }
|
||||||
|
|
||||||
class RouterView extends Component {
|
|
||||||
static props = {
|
|
||||||
keepAlive: false,
|
|
||||||
transition: false,
|
|
||||||
current: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
attribute: false,
|
|
||||||
observer(v, old) {
|
|
||||||
if (this.keepAlive && v) {
|
|
||||||
if (old && this.$refs[old]) {
|
|
||||||
this.$refs[old].deactivated()
|
|
||||||
}
|
|
||||||
this.$refs[v]?.$animate()
|
|
||||||
this.$refs[v]?.activated()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#views = []
|
|
||||||
|
|
||||||
created() {
|
|
||||||
window.__wkitd__.set('ROUTER_VIEW', this)
|
|
||||||
}
|
|
||||||
|
|
||||||
sync(views) {
|
|
||||||
this.#views = views
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let option = {
|
|
||||||
immediate: true,
|
|
||||||
custom: [
|
|
||||||
{ transform: 'translateX(-32px)', opacity: 0 },
|
|
||||||
{ transform: 'translateX(0)', opacity: 1 }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
if (this.keepAlive) {
|
|
||||||
let template = this.#views.map(it => [
|
|
||||||
this.transition
|
|
||||||
? `<${it} ref="${it}" :__keep_alive__="%s" #animation="%s" style="%s"></${it}>`
|
|
||||||
: `<${it} ref="${it}" :__keep_alive__="%s" style=%s></${it}>`,
|
|
||||||
[
|
|
||||||
this.current === it,
|
|
||||||
{ ...option, immediate: this.current === it },
|
|
||||||
this.current === it ? '' : 'display:none'
|
|
||||||
]
|
|
||||||
])
|
|
||||||
|
|
||||||
return raw(
|
|
||||||
template.map(it => it[0]).join(''),
|
|
||||||
template.map(it => it[1]).flat()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
if (this.current) {
|
|
||||||
if (this.transition) {
|
|
||||||
return raw(`<${this.current} #animation="%s"></${this.current}>`, [
|
|
||||||
option
|
|
||||||
])
|
|
||||||
}
|
|
||||||
return raw(`<${this.current}></${this.current}>`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RouterLink extends Component {
|
|
||||||
static props = {
|
|
||||||
to: Object,
|
|
||||||
disabled: false
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
:host {
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([disabled]) a {
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
#navigate() {
|
|
||||||
let type = this.$router.type
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (type === 'hash') {
|
|
||||||
//
|
|
||||||
} else {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`<a @click=${this.#navigate}> <slot></slot></a>`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!customElements.get('router-view')) {
|
|
||||||
customElements.define('router-view', RouterView)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!customElements.get('router-link')) {
|
|
||||||
customElements.define('router-link', RouterLink)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRouter(
|
export function createRouter(
|
||||||
{ history = createWebHashHistory, routes = [] } = {},
|
{ history = createWebHashHistory, routes = [] } = {},
|
||||||
options
|
options
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
//
|
||||||
|
import { Component, html, css, raw } from 'wkit'
|
||||||
|
import { object2query } from '../utils.js'
|
||||||
|
|
||||||
|
class RouterView extends Component {
|
||||||
|
static props = {
|
||||||
|
keepAlive: false,
|
||||||
|
transition: false,
|
||||||
|
current: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
attribute: false,
|
||||||
|
observer(v, old) {
|
||||||
|
if (this.keepAlive && v) {
|
||||||
|
if (old && this.$refs[old]) {
|
||||||
|
this.$refs[old].deactivated()
|
||||||
|
}
|
||||||
|
this.$refs[v]?.$animate()
|
||||||
|
this.$refs[v]?.activated()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#views = []
|
||||||
|
|
||||||
|
created() {
|
||||||
|
window.__wkitd__.set('ROUTER_VIEW', this)
|
||||||
|
}
|
||||||
|
|
||||||
|
sync(views) {
|
||||||
|
this.#views = views
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let option = {
|
||||||
|
immediate: true,
|
||||||
|
custom: [
|
||||||
|
{ transform: 'translateX(-32px)', opacity: 0 },
|
||||||
|
{ transform: 'translateX(0)', opacity: 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
if (this.keepAlive) {
|
||||||
|
let template = this.#views.map(it => [
|
||||||
|
this.transition
|
||||||
|
? `<${it} ref="${it}" :__keep_alive__="%s" #animation="%s" style="%s"></${it}>`
|
||||||
|
: `<${it} ref="${it}" :__keep_alive__="%s" style=%s></${it}>`,
|
||||||
|
[
|
||||||
|
this.current === it,
|
||||||
|
{ ...option, immediate: this.current === it },
|
||||||
|
this.current === it ? '' : 'display:none'
|
||||||
|
]
|
||||||
|
])
|
||||||
|
|
||||||
|
return raw(
|
||||||
|
template.map(it => it[0]).join(''),
|
||||||
|
template.map(it => it[1]).flat()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if (this.current) {
|
||||||
|
if (this.transition) {
|
||||||
|
return raw(`<${this.current} #animation="%s"></${this.current}>`, [
|
||||||
|
option
|
||||||
|
])
|
||||||
|
}
|
||||||
|
return raw(`<${this.current}></${this.current}>`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RouterLink extends Component {
|
||||||
|
static props = {
|
||||||
|
to: Object,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
:host {
|
||||||
|
display: inline-flex;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([disabled]) a {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
#href = ''
|
||||||
|
|
||||||
|
#navigate() {
|
||||||
|
let type = this.$router.type
|
||||||
|
let { path } = this.to
|
||||||
|
if (this.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (type === 'hash') {
|
||||||
|
location.hash = this.#href
|
||||||
|
} else {
|
||||||
|
window.history.pushState({ path }, null, this.#href)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#parsePath() {
|
||||||
|
let type = this.$router.type
|
||||||
|
let { path = '', query = {} } = this.to
|
||||||
|
let params = typeof query === 'string' ? query : object2query(query)
|
||||||
|
|
||||||
|
path = path.replace(/^\//, '')
|
||||||
|
|
||||||
|
return '/' + path + '?' + params
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.#href = this.#parsePath()
|
||||||
|
|
||||||
|
return html`<a title=${this.#href} @click=${this.#navigate}>
|
||||||
|
<slot></slot
|
||||||
|
></a>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!customElements.get('router-view')) {
|
||||||
|
customElements.define('router-view', RouterView)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!customElements.get('router-link')) {
|
||||||
|
customElements.define('router-link', RouterLink)
|
||||||
|
}
|
87
src/utils.js
87
src/utils.js
|
@ -4,6 +4,9 @@
|
||||||
* @date 2023/08/10 10:07:51
|
* @date 2023/08/10 10:07:51
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const encode = encodeURIComponent
|
||||||
|
const decode = decodeURIComponent
|
||||||
|
|
||||||
export function noop() {}
|
export function noop() {}
|
||||||
|
|
||||||
export function hideProp(host, name, value) {
|
export function hideProp(host, name, value) {
|
||||||
|
@ -26,3 +29,87 @@ export function targetIsThisWindow(target) {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* query 序列化
|
||||||
|
*/
|
||||||
|
function serialize(p, obj, callback) {
|
||||||
|
var k
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
obj.forEach(function (it, i) {
|
||||||
|
k = p ? `${p}[${Array.isArray(it) ? i : ''}]` : i
|
||||||
|
if (typeof it === 'object') {
|
||||||
|
serialize(k, it, callback)
|
||||||
|
} else {
|
||||||
|
callback(k, it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
for (let i in obj) {
|
||||||
|
k = p ? `${p}[${i}]` : i
|
||||||
|
if (typeof obj[i] === 'object') {
|
||||||
|
serialize(k, obj[i], callback)
|
||||||
|
} else {
|
||||||
|
callback(k, obj[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将url query转回json对象
|
||||||
|
*/
|
||||||
|
export function query2object(str = '') {
|
||||||
|
let params = new URLSearchParams(str)
|
||||||
|
let output = Object.create(null)
|
||||||
|
|
||||||
|
for (let [_k, _v] of params.entries()) {
|
||||||
|
let k = decode(_k)
|
||||||
|
let v = decode(_v)
|
||||||
|
let isArray = 0
|
||||||
|
|
||||||
|
if (/(\w+)\[(\w*?)\]/.test(k)) {
|
||||||
|
let k1 = RegExp.$1
|
||||||
|
let k2 = RegExp.$2
|
||||||
|
|
||||||
|
k = k1
|
||||||
|
|
||||||
|
if (!k2 || +k2 === +k2) {
|
||||||
|
v = [v]
|
||||||
|
isArray |= 2
|
||||||
|
} else {
|
||||||
|
isArray |= 1
|
||||||
|
v = { [k2]: v }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (output[k]) {
|
||||||
|
if (isArray & 2) {
|
||||||
|
output[k] = output[k].concat(v)
|
||||||
|
} else {
|
||||||
|
Object.assign(output[k], v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将json数据转成 url query字符串
|
||||||
|
*/
|
||||||
|
export function object2query(obj = {}) {
|
||||||
|
if (!obj || typeof obj === 'string' || typeof obj === 'number') {
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
let output = []
|
||||||
|
let query = function (k, v) {
|
||||||
|
output.push(k + '=' + encode(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof obj === 'object') {
|
||||||
|
serialize('', obj, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.join('&')
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue