From 66971278a28b5332d82a950ec195510719efc6a8 Mon Sep 17 00:00:00 2001 From: yutent Date: Wed, 15 Nov 2023 17:28:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0watch=E6=96=B9=E6=B3=95;?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86;?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B7=AF=E7=94=B1;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/constants.js | 2 ++ src/index.js | 2 +- src/init.js | 8 +++++- src/router/index.js | 13 +++++----- src/router/router-components.js | 25 ++++++++++++++++--- src/router/router-engine.js | 26 ++++++-------------- src/store.js | 43 +++++++++++++++++++++++++++++---- src/utils.js | 4 +-- 9 files changed, 86 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 4772a18..beb35f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wkitd", - "version": "1.2.0", + "version": "1.3.0", "type": "module", "main": "dist/index.js", "files": [ diff --git a/src/constants.js b/src/constants.js index c953ce3..df2e514 100644 --- a/src/constants.js +++ b/src/constants.js @@ -8,3 +8,5 @@ export const __ROUTER__ = Symbol('router') export const __ROUTER_VIEW__ = Symbol('router-view') export const __STORE__ = Symbol('store') export const WKITD_COMPONENTS = new Set() +export const STORE_CALLBACKS = new Map() +export const ROUTE_CALLBACKS = new Set() diff --git a/src/index.js b/src/index.js index 7a13c17..99cf407 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ import { noop, readonlyProp } from './utils.js' import { __ROUTER__, __STORE__, __ROUTER_VIEW__ } from './constants.js' export * from './router/index.js' -export { createStore } from './store.js' +export { createStore, watch } from './store.js' class App extends Component {} diff --git a/src/init.js b/src/init.js index 4500dbd..63d4e9c 100644 --- a/src/init.js +++ b/src/init.js @@ -13,20 +13,26 @@ class Wkitd extends WeakMap { */ broadcast() { for (let it of WKITD_COMPONENTS) { + if (it.removed) { + this.deassign(it) + continue + } it.$requestUpdate() } } + /** * 注册缓存组件 */ assign(target) { WKITD_COMPONENTS.add(target) } + /** * 取消注册 */ deassign(target) { - WKITD_COMPONENTS.add(target) + WKITD_COMPONENTS.delete(target) } } diff --git a/src/router/index.js b/src/router/index.js index 17575b1..a37086b 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -22,12 +22,13 @@ export function createRouter({ function wrapper() { Object.defineProperty(Component.prototype, '$router', { get() { - return window.wkitd.get(__ROUTER__) - }, - set(val) { - console.error('Can not set readonly property $router of Component') - }, - enumerable: false + return $router + } + }) + Object.defineProperty(Component.prototype, '$route', { + get() { + return $router.route + } }) } wrapper.beforeEach = $router.beforeEach.bind($router) diff --git a/src/router/router-components.js b/src/router/router-components.js index db7b8d5..2ca7002 100644 --- a/src/router/router-components.js +++ b/src/router/router-components.js @@ -1,7 +1,8 @@ // import { Component, html, css, raw } from 'wkit' 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 { static props = { @@ -24,6 +25,7 @@ class RouterView extends Component { if (this.keepAlive) { if (old) { if (this.$refs[old]) { + this.$refs[old].removed = true this.$refs[old].deactivated() this.$refs[old].remove() } else { @@ -39,6 +41,7 @@ class RouterView extends Component { if (this.transition) { this.$refs[v].$animate() } + this.$refs[v].removed = false this.$refs[v].activated() } else { this.$requestUpdate() @@ -150,16 +153,30 @@ class RouterLink extends Component { return '/' + path } + activated() { + this.mounted() + } + deactivated() { + this.unmounted() + } + mounted() { - this.$router.rsync(this, route => { + watch('$route', route => { + if (this.removed) { + return + } this.classList.toggle('active', route.path === this.to.path) }) } + unmounted() { + ROUTE_CALLBACKS.delete(this) + } + render() { this.#href = this.#parsePath() - return html` - ` } } diff --git a/src/router/router-engine.js b/src/router/router-engine.js index 77e2022..a4b0686 100644 --- a/src/router/router-engine.js +++ b/src/router/router-engine.js @@ -6,7 +6,7 @@ */ import { bind, fire } from 'wkit' import { noop, query2object, object2query } from '../utils.js' -import { __ROUTER_VIEW__ } from '../constants.js' +import { __ROUTER_VIEW__, ROUTE_CALLBACKS } from '../constants.js' //hash前缀正则 const PREFIX_REGEXP = /^(#!|#)[\/]+?/ @@ -21,8 +21,6 @@ class Router { #tables = new Map() #views = new Set() - #targets = new Map() - #ready = false #route = Object.create(null) @@ -146,12 +144,15 @@ class Router { let $view = window.wkitd.get(__ROUTER_VIEW__) $view.current = route.name this.#route = route - this.#rsync() + this.#broadcast() } - #rsync() { - for (let [target, callback] of this.#targets) { - callback.call(target, this.route) + // 广播通知 + #broadcast() { + if (this.#ready) { + for (let callback of ROUTE_CALLBACKS) { + callback(this.route) + } } } @@ -162,17 +163,6 @@ class Router { this.#hashchange() } - /** - * 用于同步路由到组件的 - */ - rsync(target, callback) { - this.#targets.set(target, callback) - // 路由已经初始化完成时, 还有新的同步请求则立刻执行 - if (this.#ready) { - this.#rsync() - } - } - beforeEach(callback = noop) { this.#beforeEach = callback } diff --git a/src/store.js b/src/store.js index 1929c08..b21494f 100644 --- a/src/store.js +++ b/src/store.js @@ -5,9 +5,15 @@ */ 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) { return obj } @@ -17,24 +23,52 @@ function observe(obj) { let value = Reflect.get(target, key, receiver) // 当访问的值是对象时,需要对这个对象也进行代理 if (typeof value === 'object') { - return observe(value) + return observe(value, paths.concat(key)) } return value }, set(target, key, value, receiver) { + let full = paths.concat(key).join('.') + if (target[key] === value) { + return true + } Reflect.set(target, key, value, receiver) + if (STORE_CALLBACKS.get(full)) { + STORE_CALLBACKS.get(full).forEach(callback => { + callback(value) + }) + } window.wkitd.broadcast() 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 = {}) { let defined = false return function () { Object.defineProperty(Component.prototype, '$store', { get() { + window.wkitd.assign(this) return window.wkitd.get(__STORE__) }, set(val) { @@ -45,8 +79,7 @@ export function createStore(obj = {}) { } window.wkitd.set(__STORE__, observe(val)) defined = true - }, - enumerable: false + } }) Component.prototype.$store = obj } diff --git a/src/utils.js b/src/utils.js index ef155ca..bd51e20 100644 --- a/src/utils.js +++ b/src/utils.js @@ -13,9 +13,7 @@ export function readonlyProp(host, name, value) { Object.defineProperty(host, name, { get() { return value - }, - set(vale) {}, - enumerable: false + } }) }