From 4e828fbc70720d83554a1c3d2393ed70fe009d0d Mon Sep 17 00:00:00 2001 From: neverland Date: Mon, 19 Aug 2019 11:04:25 +0800 Subject: [PATCH] [bugfix] Tabbar: avoid navigation duplicated (#4147) --- package.json | 2 +- src/tabbar/test/index.spec.js | 41 ++++++++++++++++++++++++++--------- src/utils/router.ts | 16 +++++++++++--- yarn.lock | 8 +++---- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 7e61ca933..560d1f8dc 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "vue": "2.6.10", "vue-jest": "4.0.0-beta.2", "vue-loader": "^15.7.1", - "vue-router": "^3.0.7", + "vue-router": "^3.1.2", "vue-template-compiler": "2.6.10", "webpack": "4.39.1", "webpack-cli": "^3.3.6", diff --git a/src/tabbar/test/index.spec.js b/src/tabbar/test/index.spec.js index 116fe1951..e5edbf7c3 100644 --- a/src/tabbar/test/index.spec.js +++ b/src/tabbar/test/index.spec.js @@ -1,3 +1,4 @@ +import VueRouter from 'vue-router'; import { mount, later } from '../../../test/utils'; import Vue from 'vue'; import Tabbar from '..'; @@ -5,20 +6,15 @@ import TabbarItem from '../../tabbar-item'; Vue.use(Tabbar); Vue.use(TabbarItem); +Vue.use(VueRouter); test('route mode', async () => { - Vue.util.defineReactive(Vue.prototype, '$route', { path: '/home' }); - - Vue.prototype.$router = { - replace(to) { - Vue.prototype.$route.path = typeof to === 'string' ? to : to.path; - } - }; - + const router = new VueRouter(); const wrapper = mount({ + router, template: ` - + Tab @@ -48,6 +44,28 @@ test('route mode', async () => { expect(wrapper).toMatchSnapshot(); }); +test('router NavigationDuplicated', async done => { + expect(async () => { + const router = new VueRouter(); + const wrapper = mount({ + router, + template: ` + + + Tab + + + ` + }); + + const item = wrapper.find('.van-tabbar-item'); + item.trigger('click'); + item.trigger('click'); + + await later(); + done(); + }).not.toThrow(); +}); test('watch tabbar value', () => { const wrapper = mount({ @@ -108,7 +126,10 @@ test('name prop', () => { } }); - wrapper.findAll('.van-tabbar-item').at(1).trigger('click'); + wrapper + .findAll('.van-tabbar-item') + .at(1) + .trigger('click'); expect(onChange).toHaveBeenCalledWith('b'); }); diff --git a/src/utils/router.ts b/src/utils/router.ts index 3c61c0ab0..6bc9e771f 100644 --- a/src/utils/router.ts +++ b/src/utils/router.ts @@ -14,7 +14,17 @@ export type RouteConfig = { export function route(router: VueRouter, config: RouteConfig) { const { to, url, replace } = config; if (to && router) { - router[replace ? 'replace' : 'push'](to); + const promise = router[replace ? 'replace' : 'push'](to); + + /* istanbul ignore else */ + if (promise && promise.catch) { + promise.catch(err => { + /* istanbul ignore if */ + if (err.name !== 'NavigationDuplicated') { + throw err; + } + }); + } } else if (url) { replace ? location.replace(url) : (location.href = url); } @@ -25,10 +35,10 @@ export function functionalRoute(context: RenderContext) { } export type RouteProps = { - url?: string, + url?: string; replace?: boolean; to?: RawLocation; -} +}; export const routeProps = { url: String, diff --git a/yarn.lock b/yarn.lock index dc4edc900..701e4abc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10089,10 +10089,10 @@ vue-loader@^15.7.1: vue-hot-reload-api "^2.3.0" vue-style-loader "^4.1.0" -vue-router@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b" - integrity sha512-utJ+QR3YlIC/6x6xq17UMXeAfxEvXA0VKD3PiSio7hBOZNusA1jXcbxZxVEfJunLp48oonjTepY8ORoIlRx/EQ== +vue-router@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.2.tgz#2e0904703545dabdd42b2b7a2e617f02f99a1969" + integrity sha512-WssQEHSEvIS1/CI4CO2T8LJdoK4Q9Ngox28K7FDNMTfzNTk2WS5D0dDlqYCaPG+AG4Z8wJkn1KrBc7AhspZJUQ== vue-style-loader@^4.1.0: version "4.1.2"