增加watch方法;优化状态管理;优化路由;
parent
1cddfb6731
commit
66971278a2
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "wkitd",
|
"name": "wkitd",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
@ -8,3 +8,5 @@ export const __ROUTER__ = Symbol('router')
|
||||||
export const __ROUTER_VIEW__ = Symbol('router-view')
|
export const __ROUTER_VIEW__ = Symbol('router-view')
|
||||||
export const __STORE__ = Symbol('store')
|
export const __STORE__ = Symbol('store')
|
||||||
export const WKITD_COMPONENTS = new Set()
|
export const WKITD_COMPONENTS = new Set()
|
||||||
|
export const STORE_CALLBACKS = new Map()
|
||||||
|
export const ROUTE_CALLBACKS = new Set()
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { noop, readonlyProp } from './utils.js'
|
||||||
import { __ROUTER__, __STORE__, __ROUTER_VIEW__ } from './constants.js'
|
import { __ROUTER__, __STORE__, __ROUTER_VIEW__ } from './constants.js'
|
||||||
|
|
||||||
export * from './router/index.js'
|
export * from './router/index.js'
|
||||||
export { createStore } from './store.js'
|
export { createStore, watch } from './store.js'
|
||||||
|
|
||||||
class App extends Component {}
|
class App extends Component {}
|
||||||
|
|
||||||
|
|
|
@ -13,20 +13,26 @@ class Wkitd extends WeakMap {
|
||||||
*/
|
*/
|
||||||
broadcast() {
|
broadcast() {
|
||||||
for (let it of WKITD_COMPONENTS) {
|
for (let it of WKITD_COMPONENTS) {
|
||||||
|
if (it.removed) {
|
||||||
|
this.deassign(it)
|
||||||
|
continue
|
||||||
|
}
|
||||||
it.$requestUpdate()
|
it.$requestUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册缓存组件
|
* 注册缓存组件
|
||||||
*/
|
*/
|
||||||
assign(target) {
|
assign(target) {
|
||||||
WKITD_COMPONENTS.add(target)
|
WKITD_COMPONENTS.add(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消注册
|
* 取消注册
|
||||||
*/
|
*/
|
||||||
deassign(target) {
|
deassign(target) {
|
||||||
WKITD_COMPONENTS.add(target)
|
WKITD_COMPONENTS.delete(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,13 @@ export function createRouter({
|
||||||
function wrapper() {
|
function wrapper() {
|
||||||
Object.defineProperty(Component.prototype, '$router', {
|
Object.defineProperty(Component.prototype, '$router', {
|
||||||
get() {
|
get() {
|
||||||
return window.wkitd.get(__ROUTER__)
|
return $router
|
||||||
},
|
}
|
||||||
set(val) {
|
})
|
||||||
console.error('Can not set readonly property $router of Component')
|
Object.defineProperty(Component.prototype, '$route', {
|
||||||
},
|
get() {
|
||||||
enumerable: false
|
return $router.route
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
wrapper.beforeEach = $router.beforeEach.bind($router)
|
wrapper.beforeEach = $router.beforeEach.bind($router)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
//
|
//
|
||||||
import { Component, html, css, raw } from 'wkit'
|
import { Component, html, css, raw } from 'wkit'
|
||||||
import { object2query } from '../utils.js'
|
import { object2query } from '../utils.js'
|
||||||
import { __ROUTER_VIEW__ } from '../constants.js'
|
import { __ROUTER_VIEW__, ROUTE_CALLBACKS } from '../constants.js'
|
||||||
|
import { watch } from '../store.js'
|
||||||
|
|
||||||
class RouterView extends Component {
|
class RouterView extends Component {
|
||||||
static props = {
|
static props = {
|
||||||
|
@ -24,6 +25,7 @@ class RouterView extends Component {
|
||||||
if (this.keepAlive) {
|
if (this.keepAlive) {
|
||||||
if (old) {
|
if (old) {
|
||||||
if (this.$refs[old]) {
|
if (this.$refs[old]) {
|
||||||
|
this.$refs[old].removed = true
|
||||||
this.$refs[old].deactivated()
|
this.$refs[old].deactivated()
|
||||||
this.$refs[old].remove()
|
this.$refs[old].remove()
|
||||||
} else {
|
} else {
|
||||||
|
@ -39,6 +41,7 @@ class RouterView extends Component {
|
||||||
if (this.transition) {
|
if (this.transition) {
|
||||||
this.$refs[v].$animate()
|
this.$refs[v].$animate()
|
||||||
}
|
}
|
||||||
|
this.$refs[v].removed = false
|
||||||
this.$refs[v].activated()
|
this.$refs[v].activated()
|
||||||
} else {
|
} else {
|
||||||
this.$requestUpdate()
|
this.$requestUpdate()
|
||||||
|
@ -150,16 +153,30 @@ class RouterLink extends Component {
|
||||||
return '/' + path
|
return '/' + path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activated() {
|
||||||
|
this.mounted()
|
||||||
|
}
|
||||||
|
deactivated() {
|
||||||
|
this.unmounted()
|
||||||
|
}
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$router.rsync(this, route => {
|
watch('$route', route => {
|
||||||
|
if (this.removed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.classList.toggle('active', route.path === this.to.path)
|
this.classList.toggle('active', route.path === this.to.path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unmounted() {
|
||||||
|
ROUTE_CALLBACKS.delete(this)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.#href = this.#parsePath()
|
this.#href = this.#parsePath()
|
||||||
return html`<a title=${this.#href} @click=${this.#navigate}>
|
return html`<a title=${this.#href} @click=${this.#navigate}
|
||||||
<slot></slot
|
><slot></slot
|
||||||
></a>`
|
></a>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
import { bind, fire } from 'wkit'
|
import { bind, fire } from 'wkit'
|
||||||
import { noop, query2object, object2query } from '../utils.js'
|
import { noop, query2object, object2query } from '../utils.js'
|
||||||
import { __ROUTER_VIEW__ } from '../constants.js'
|
import { __ROUTER_VIEW__, ROUTE_CALLBACKS } from '../constants.js'
|
||||||
|
|
||||||
//hash前缀正则
|
//hash前缀正则
|
||||||
const PREFIX_REGEXP = /^(#!|#)[\/]+?/
|
const PREFIX_REGEXP = /^(#!|#)[\/]+?/
|
||||||
|
@ -21,8 +21,6 @@ class Router {
|
||||||
#tables = new Map()
|
#tables = new Map()
|
||||||
#views = new Set()
|
#views = new Set()
|
||||||
|
|
||||||
#targets = new Map()
|
|
||||||
|
|
||||||
#ready = false
|
#ready = false
|
||||||
#route = Object.create(null)
|
#route = Object.create(null)
|
||||||
|
|
||||||
|
@ -146,12 +144,15 @@ class Router {
|
||||||
let $view = window.wkitd.get(__ROUTER_VIEW__)
|
let $view = window.wkitd.get(__ROUTER_VIEW__)
|
||||||
$view.current = route.name
|
$view.current = route.name
|
||||||
this.#route = route
|
this.#route = route
|
||||||
this.#rsync()
|
this.#broadcast()
|
||||||
}
|
}
|
||||||
|
|
||||||
#rsync() {
|
// 广播通知
|
||||||
for (let [target, callback] of this.#targets) {
|
#broadcast() {
|
||||||
callback.call(target, this.route)
|
if (this.#ready) {
|
||||||
|
for (let callback of ROUTE_CALLBACKS) {
|
||||||
|
callback(this.route)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,17 +163,6 @@ class Router {
|
||||||
this.#hashchange()
|
this.#hashchange()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 用于同步路由到组件的
|
|
||||||
*/
|
|
||||||
rsync(target, callback) {
|
|
||||||
this.#targets.set(target, callback)
|
|
||||||
// 路由已经初始化完成时, 还有新的同步请求则立刻执行
|
|
||||||
if (this.#ready) {
|
|
||||||
this.#rsync()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(callback = noop) {
|
beforeEach(callback = noop) {
|
||||||
this.#beforeEach = callback
|
this.#beforeEach = callback
|
||||||
}
|
}
|
||||||
|
|
43
src/store.js
43
src/store.js
|
@ -5,9 +5,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component } from 'wkit'
|
import { Component } from 'wkit'
|
||||||
import { __STORE__ } from './constants.js'
|
import {
|
||||||
|
__STORE__,
|
||||||
|
__ROUTER__,
|
||||||
|
STORE_CALLBACKS,
|
||||||
|
ROUTE_CALLBACKS
|
||||||
|
} from './constants.js'
|
||||||
|
import { noop } from './utils.js'
|
||||||
|
|
||||||
function observe(obj) {
|
function observe(obj, paths = ['$store']) {
|
||||||
if (obj === null) {
|
if (obj === null) {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
@ -17,24 +23,52 @@ function observe(obj) {
|
||||||
let value = Reflect.get(target, key, receiver)
|
let value = Reflect.get(target, key, receiver)
|
||||||
// 当访问的值是对象时,需要对这个对象也进行代理
|
// 当访问的值是对象时,需要对这个对象也进行代理
|
||||||
if (typeof value === 'object') {
|
if (typeof value === 'object') {
|
||||||
return observe(value)
|
return observe(value, paths.concat(key))
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
},
|
},
|
||||||
set(target, key, value, receiver) {
|
set(target, key, value, receiver) {
|
||||||
|
let full = paths.concat(key).join('.')
|
||||||
|
if (target[key] === value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
Reflect.set(target, key, value, receiver)
|
Reflect.set(target, key, value, receiver)
|
||||||
|
if (STORE_CALLBACKS.get(full)) {
|
||||||
|
STORE_CALLBACKS.get(full).forEach(callback => {
|
||||||
|
callback(value)
|
||||||
|
})
|
||||||
|
}
|
||||||
window.wkitd.broadcast()
|
window.wkitd.broadcast()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function watch(key, callback = noop) {
|
||||||
|
if (key.startsWith('$store.')) {
|
||||||
|
let list = STORE_CALLBACKS.get(key)
|
||||||
|
if (list) {
|
||||||
|
list.add(callback)
|
||||||
|
} else {
|
||||||
|
list = new Set()
|
||||||
|
list.add(callback)
|
||||||
|
STORE_CALLBACKS.set(key, list)
|
||||||
|
}
|
||||||
|
} else if (key.startsWith('$route')) {
|
||||||
|
ROUTE_CALLBACKS.add(callback)
|
||||||
|
callback(window.wkitd.get(__ROUTER__).route)
|
||||||
|
} else {
|
||||||
|
return console.error('watch() only work on $store and $route')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function createStore(obj = {}) {
|
export function createStore(obj = {}) {
|
||||||
let defined = false
|
let defined = false
|
||||||
|
|
||||||
return function () {
|
return function () {
|
||||||
Object.defineProperty(Component.prototype, '$store', {
|
Object.defineProperty(Component.prototype, '$store', {
|
||||||
get() {
|
get() {
|
||||||
|
window.wkitd.assign(this)
|
||||||
return window.wkitd.get(__STORE__)
|
return window.wkitd.get(__STORE__)
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
|
@ -45,8 +79,7 @@ export function createStore(obj = {}) {
|
||||||
}
|
}
|
||||||
window.wkitd.set(__STORE__, observe(val))
|
window.wkitd.set(__STORE__, observe(val))
|
||||||
defined = true
|
defined = true
|
||||||
},
|
}
|
||||||
enumerable: false
|
|
||||||
})
|
})
|
||||||
Component.prototype.$store = obj
|
Component.prototype.$store = obj
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,7 @@ export function readonlyProp(host, name, value) {
|
||||||
Object.defineProperty(host, name, {
|
Object.defineProperty(host, name, {
|
||||||
get() {
|
get() {
|
||||||
return value
|
return value
|
||||||
},
|
}
|
||||||
set(vale) {},
|
|
||||||
enumerable: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue