11

我们都知道 vue-router 的动态路由匹配 对组件是原地复用的策略,需要我们在组件中根据不同的$route参数展示不同的数据,这在大部分情景下是很高效的做法,但这无疑增加了组件的复杂度,而且不同参数间切换因为是同组件复用,切换效果不加修饰的话会显得很生硬,这里放一张图片感受一下。
SingleView
如果我们希望能够每个动态参数都能渲染出一个组件而不是去复用怎么办呢?
我这里提供一个简便的方案
通常动态路由我们都是用来处理详情页

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User, props: true }
  ]
})

User.vue

<template>
  <div>{{ user.name }}</div>
</template>
<script>
  export default {
    name: 'User',
    props: ['id'],
    data() {
      return {data: {}};
    },
    watch: {
      id(id) {
        this.getUser(id);
      },
    },
    computed: {
      user() {
        return this.data[this.id] || {name: ''};
      },
    },
    methods: {
      getUser(id) {
        setTimeout(() => {  // 假装异步
          this.data[id] = {id, name: '张' + id};
        }, 1000);
      },
    },
    mounted() {
      this.getUser(this.id);
    },
  };
</script>

我们可以发现基本上这样的组件是围绕着 路径参数 即例子中的id做处理和渲染,只要我们能提取到这个路径参数,并维护成列表,通过这个列表来渲染实际组件,然后通过v-show显示当前路径参数下的组件,就可以实现不同参数不同组件的效果了。
简单的来个例子

<template>
  <div>
    <user
        v-for="_id in idList"
        v-show="_id === id"
        :id="_id"
        :key="_id"
    />
  </div>
</template>
<script>
  import User from './User.vue';

  export default {
    name: 'UserPage',
    components: {
      User,
    },
    props: ['id'],
    data() {
      return {
        idList: [this.id],
      };
    },
    watch: {
      id(id) {
        if (!this.idList.includes(id)) this.idList.push(id);
      },
    },
  };
</script>

然后把这个组件作为router组件

{ path: '/user/:id', component: UserPage, props: true }

现在我们完成解耦,同路由组件间参数转变切换的是真实组件了,这里再放一张图片感受一下。
MultiView
这个方案说明白了很简单,但还是有一些细节要注意处理,比如记录不同参数页面的滚动条高度,比如怎么处理子页面关闭等等,我的开源项目e-admin提供的ea-view组件对这个解决方案做了完整的细节处理,有兴趣的话可以参考一下 ea-view
我正在造一个基于element-ui的中后台框架轮子 e-admin 欢迎star


asseek
9.4k 声望288 粉丝

认真到底,终有回响