diff --git a/.editorconfig b/.editorconfig index 7053c49a045c91bd8b3015c1cf3d1f6da21660d8..647c488ad8c9c84869ca12c8e2e3bd064f28eaaf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,9 @@ -[*.{js,jsx,ts,tsx,vue}] +root = true + +[*] indent_style = space -indent_size = 2 trim_trailing_whitespace = true insert_final_newline = true + +[*.{js,jsx,ts,tsx,vue,html}] +indent_size = 2 diff --git a/.eslintignore b/.eslintignore index a9a19052c715aa3a25c4016f51f1348391d603b1..787c1c24a8f5b2439eac5ff1a0f406ead26a351f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,3 +2,4 @@ /config/ /dist/ ./*.js +/example/router.js diff --git a/.gitignore b/.gitignore index ad46b30886fa350c1f59761b100e5e4b01f9a7ec..ad4f14a517ae9d536c6044f8f5d8eaddcbb8032e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +# Editor +.idea +.vscode +.vs + # Logs logs *.log diff --git a/README.md b/README.md index ae71176773da47971ec495f37ca3bde5d379217d..0be2ea46eb4e795a481a88721f378b6c4012d1ec 100644 --- a/README.md +++ b/README.md @@ -108,12 +108,29 @@ $route(to, from) { ``` [example](https://github.com/hezhongfeng/vue-page-stack-example/blob/master/src/App.vue) -### get current UI stack +### Methods +```javascript +this.$pageStack.getStack() +this.$pageStack.setStack() +this.$pageStack.clearStack() ``` -let UIStack = this.$pageStack.getStack(); +|Method|Description| +|:----:|:----| +|getStack|get stackList| +|setStack|set StackList| +|clearStack|clear StackList| +### Advanced usage +```javascript +// clear Stack then push +// is method clearStack +this.$router.clearPush({name: 'Home'}) + +// Finds the specified page in the stack, clears the subsequent stack, and then push +// is method setStack +this.$router.backReplace({name: 'List'}) ``` -[example code](https://github.com/hezhongfeng/vue-page-stack-example/blob/814f5ad8b8804e6fd81002f7254d266df3311770/src/views/main/MainList.vue#L30) + ## Notes ### keyName diff --git a/README.zh-cn.md b/README.zh-cn.md index 162e0c90439b7051c666b4382ea179ac55e999e5..57cc8d9725576ba35bc350ec9ce32e330e5e5020 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -116,11 +116,28 @@ $route(to, from) { [example](https://github.com/hezhongfeng/vue-page-stack-example/blob/master/src/App.vue) -### 获取当前UI栈 +### 方法 +```javascript +this.$pageStack.getStack() +this.$pageStack.setStack() +this.$pageStack.clearStack() +``` +|方法|说明| +|:----:|:----| +|getStack|获取页面栈| +|setStack|设置页面栈| +|clearStack|清空页面栈| + +### 高级用法 +```javascript +// 清空页面栈,然后 push +// 使用方法 clearStack +this.$router.clearPush({name: 'Home'}) + +// 找到指定页面,清除后续页面,然后 replace +// 使用方法 setStack +this.$router.backReplace({name: 'List'}) ``` -let UIStack = this.$pageStack.getStack(); -``` -[example code](https://github.com/hezhongfeng/vue-page-stack-example/blob/814f5ad8b8804e6fd81002f7254d266df3311770/src/views/main/MainList.vue#L30) ## 相关说明 diff --git a/example/App.vue b/example/App.vue new file mode 100644 index 0000000000000000000000000000000000000000..f1024453ebbc49e4dedec399c673d13b43489a96 --- /dev/null +++ b/example/App.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/example/index.html b/example/index.html new file mode 100644 index 0000000000000000000000000000000000000000..4af7e546eba1f0b245c7d60a1c004b6a6765aafe --- /dev/null +++ b/example/index.html @@ -0,0 +1,15 @@ + + + + + + + VuePageStack - Example + + + +
+ + + diff --git a/example/main.js b/example/main.js new file mode 100644 index 0000000000000000000000000000000000000000..3f183174242c22344a3dd18719768ee4c790c67f --- /dev/null +++ b/example/main.js @@ -0,0 +1,12 @@ +import Vue from 'vue'; +import App from './App.vue'; +import router from './router'; +import VuePageStack from '../src'; + +Vue.config.productionTip = false; +Vue.use(VuePageStack, { router }); + +window.vm = new Vue({ + router, + render: h => h(App) +}).$mount('#app'); diff --git a/example/pages/CharactersIntro.vue b/example/pages/CharactersIntro.vue new file mode 100644 index 0000000000000000000000000000000000000000..7cd71a937bc20a07634029dd21166d74b18e256c --- /dev/null +++ b/example/pages/CharactersIntro.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/example/pages/Home.vue b/example/pages/Home.vue new file mode 100644 index 0000000000000000000000000000000000000000..c42a2b41b1ce328a355c83e035d87c816a6eed05 --- /dev/null +++ b/example/pages/Home.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/example/pages/article/ArticlePage.vue b/example/pages/article/ArticlePage.vue new file mode 100644 index 0000000000000000000000000000000000000000..0624fd5674ec07c5132edefac0593f08978b04b3 --- /dev/null +++ b/example/pages/article/ArticlePage.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/example/pages/article/List.vue b/example/pages/article/List.vue new file mode 100644 index 0000000000000000000000000000000000000000..1f9638c7bf28d0184ca91dedc88d9888f207dadc --- /dev/null +++ b/example/pages/article/List.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/example/router.js b/example/router.js new file mode 100644 index 0000000000000000000000000000000000000000..042b187178b47f51ce8af2df97a8e410264e6d14 --- /dev/null +++ b/example/router.js @@ -0,0 +1,14 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' + +Vue.use(VueRouter) + +export default new VueRouter({ + mode: 'hash', + routes: [ + {path: '/', name: 'Home', component: () => import('./pages/Home')}, + {path: '/characters-intro/:name', name: 'CharactersIntro', component: () => import('./pages/CharactersIntro')}, + {path: '/article', name: 'List', component: () => import('./pages/article/List')}, + {path: '/article/:id', name: 'Article', component: () => import('./pages/article/ArticlePage')} + ] +}) diff --git a/package.json b/package.json index 440de7bddf242c932a9af0bf8a21e09daf9722c4..e7b9808b372c3fee2fdbb07b02ea0cfbfd98af04 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,12 @@ "description": "Routing and navigation for your Vue SPA. Vue 单页应用导航管理器", "author": "hezf", "scripts": { + "dev": "vue-cli-service serve ./example/main.js", "test:unit": "vue-cli-service test:unit", "build": "vue-cli-service build --target lib --name vue-page-stack ./src/index.js", "lint": "vue-cli-service lint" }, - "main": "dist/vue-page-stack.common.js", + "main": "src/index.js", "dependencies": {}, "devDependencies": { "@vue/cli-plugin-babel": "^3.11.0", @@ -22,6 +23,8 @@ "babel-jest": "^23.6.0", "eslint": "^5.16.0", "eslint-plugin-vue": "^5.0.0", + "less": "^3.10.3", + "less-loader": "^5.0.0", "vue": "^2.6.10", "vue-router": "^3.1.3", "vue-template-compiler": "^2.6.10" diff --git a/src/components/VuePageStack.js b/src/components/VuePageStack.js index 87f39dbf4a8e40e7b95856e3e1d7fa29a4cfc13d..c6dc11e38ca9db691f874600ded92cb3e5a6ad82 100644 --- a/src/components/VuePageStack.js +++ b/src/components/VuePageStack.js @@ -20,7 +20,7 @@ function getFirstComponentChild(children) { } } -const stack = []; +let stack = []; function getIndexByKey(key) { for (let index = 0; index < stack.length; index++) { @@ -53,6 +53,9 @@ let VuePageStack = keyName => { if (!vnode) { return vnode; } + if (history.action === config.clearPushName) { + clearStack(); + } let index = getIndexByKey(key); if (index !== -1) { vnode.componentInstance = stack[index].vnode.componentInstance; @@ -81,4 +84,15 @@ function getStack() { return stack; } -export { VuePageStack, getIndexByKey, getStack }; +function setStack(list) { + stack = list; +} + +function clearStack() { + for (const item of stack) { + item.vnode.componentInstance.$destroy(); + } + stack = []; +} + +export { VuePageStack, getIndexByKey, getStack, setStack, clearStack }; diff --git a/src/config/config.js b/src/config/config.js index 4d1d8565f6ade83e973550f31b316d56d2d2124c..2eaa8eb11c0addfdbb4db5694eb1abe0ef0e4ed2 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -4,6 +4,8 @@ export default { pushName: 'push', goName: 'go', replaceName: 'replace', + clearPushName: 'clearPush', + backPushName: 'backPush', backName: 'back', forwardName: 'forward' }; diff --git a/src/index.js b/src/index.js index 0f25484d6de3c1e95c0d5241ca9d5806b173081b..076068a8d79e89171a0304026593984c34fdac1c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import { VuePageStack, getIndexByKey, getStack } from './components/VuePageStack'; +import { VuePageStack, getIndexByKey, getStack, setStack, clearStack } from './components/VuePageStack'; import mixin from './mixin'; import history from './history'; import config from './config/config'; @@ -32,9 +32,11 @@ VuePageStackPlugin.install = function(Vue, { router, name = config.componentName throw Error('\n vue-router is necessary. \n\n'); } Vue.component(name, VuePageStack(keyName)); - + Vue.prototype.$pageStack = { - getStack + getStack, + setStack, + clearStack }; mixin(router); diff --git a/src/mixin.js b/src/mixin.js index a781440053c6a51c2c9dd48975465c4e8139ba15..5416b8b408313ed0528c4badfd81eada76a62eca 100644 --- a/src/mixin.js +++ b/src/mixin.js @@ -1,5 +1,6 @@ import history from './history'; import config from './config/config'; +import { getStack, setStack } from './components/VuePageStack'; let eventRegister = function(router) { const routerPush = router.push.bind(router); @@ -8,8 +9,7 @@ let eventRegister = function(router) { const routerBack = router.back.bind(router); const routerForward = router.forward.bind(router); - router.push = (location, onResolve, onReject) => { - history.action = config.pushName; + const _push = function(location, onResolve, onReject) { if (onResolve || onReject) { return routerPush(location, onResolve, onReject); } @@ -19,14 +19,7 @@ let eventRegister = function(router) { } }); }; - - router.go = n => { - history.action = config.goName; - routerGo(n); - }; - - router.replace = (location, onResolve, onReject) => { - history.action = config.replaceName; + const _replace = function(location, onResolve, onReject) { if (onResolve || onReject) { return routerReplace(location, onResolve, onReject); } @@ -37,6 +30,59 @@ let eventRegister = function(router) { }); }; + router.push = (location, onResolve, onReject) => { + history.action = config.pushName; + _push(location, onResolve, onReject); + }; + + router.clearPush = (location, onResolve, onReject) => { + history.action = config.clearPushName; + _push(location, onResolve, onReject); + }; + + router.replace = (location, onResolve, onReject) => { + history.action = config.replaceName; + _replace(location, onResolve, onReject); + }; + + router.backReplace = (location, onResolve, onReject) => { + history.action = config.replaceName; + + const list = getStack(); + let len = 0; + for (const i in list) { + if (list.hasOwnProperty(i)) { + const vnode = list[i].vnode; + if (vnode.componentOptions.Ctor.extendOptions.name === 'List') { + len = i; + } + } + } + + let arr = []; + for (const i in list) { + if (list.hasOwnProperty(i)) { + const vnode = list[i].vnode; + if (i > len) { + vnode.componentInstance.$destroy(); + } else { + arr.push({ + key: list[i].key, + vnode + }); + } + } + } + + setStack(arr); + _replace(location, onResolve, onReject); + }; + + router.go = n => { + history.action = config.goName; + routerGo(n); + }; + router.back = () => { history.action = config.backName; routerBack(); diff --git a/vue.config.js b/vue.config.js index 9caf12e76cffe59c81174ea01a2ccfb1cc8f0632..ebb5891684ae1265d46276e87d8c457d5cee2b14 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,6 +1,6 @@ module.exports = { - css: { - extract: false + css: { + extract: false }, productionSourceMap: true, configureWebpack: { diff --git a/yarn.lock b/yarn.lock index 4b65ffe8bc4f7d343bd7a3e03ac94afbc8a8776b..fc71b0ed4a2f74d53ff0a93a2de3a876ef25212c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1572,6 +1572,11 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.npm.taobao.org/asap/download/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.npm.taobao.org/asn1.js/download/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -2493,7 +2498,7 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -clone@2.x: +clone@2.x, clone@^2.1.1, clone@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= @@ -3494,7 +3499,7 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== -errno@^0.1.3, errno@~0.1.7: +errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "http://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" integrity sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg= @@ -4965,6 +4970,11 @@ ignore@^5.0.2: resolved "http://registry.npm.taobao.org/ignore/download/ignore-5.0.5.tgz#c663c548d6ce186fb33616a8ccb5d46e56bdbbf9" integrity sha1-xmPFSNbOGG+zNhaozLXUbla9u/k= +image-size@~0.5.0: + version "0.5.5" + resolved "https://registry.npm.taobao.org/image-size/download/image-size-0.5.5.tgz?cache=0&sync_timestamp=1569841504754&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimage-size%2Fdownload%2Fimage-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" + integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -6145,6 +6155,31 @@ left-pad@^1.3.0: resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== +less-loader@^5.0.0: + version "5.0.0" + resolved "https://registry.npm.taobao.org/less-loader/download/less-loader-5.0.0.tgz#498dde3a6c6c4f887458ee9ed3f086a12ad1b466" + integrity sha1-SY3eOmxsT4h0WO6e0/CGoSrRtGY= + dependencies: + clone "^2.1.1" + loader-utils "^1.1.0" + pify "^4.0.1" + +less@^3.10.3: + version "3.10.3" + resolved "https://registry.npm.taobao.org/less/download/less-3.10.3.tgz#417a0975d5eeecc52cff4bcfa3c09d35781e6792" + integrity sha1-QXoJddXu7MUs/0vPo8CdNXgeZ5I= + dependencies: + clone "^2.1.2" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + mime "^1.4.1" + mkdirp "^0.5.0" + promise "^7.1.1" + request "^2.83.0" + source-map "~0.6.0" + leven@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" @@ -6517,7 +6552,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.40.0" -mime@1.6.0: +mime@1.6.0, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -7915,6 +7950,13 @@ promise-inflight@^1.0.1: resolved "https://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078= + dependencies: + asap "~2.0.3" + prompts@^0.1.9: version "0.1.14" resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.14.tgz#a8e15c612c5c9ec8f8111847df3337c9cbd443b2" @@ -8338,7 +8380,7 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.7: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.87.0: +request@^2.83.0, request@^2.87.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==