Vue使用动态组件或者router时,当多个视图使用/指向同一个组件时,如何能够生成多个新实例?

我的需求:

我希望做一个列表组件,其list在组件内部自行管理;
我的SPA上有n个视图(动态生成),每个视图都使用上述组件,在动态组件和vue-router的方式下发现,组件其实并没有生成多个实例。

查阅了资料和写了demo,发现好像只有显式使用组件tag或new出来挂载才会生成新实例。

看了一些别人写的demo,发现是用的其实就是同一个组件,同一个实例,只是每个视图传的data渲染不一样,这样实现或许更符合mvvm的思维。

但是我想知道,Vue是不推荐每一个视图都生成新实例呢?还是我的理解有误?存在动态生成视图并生成对应新实例的方法吗?

(有这个想法的原因可能是因我希望保留每一个页面的dom和data,不想每次切页面的时候重新渲染,对应不同视图用不同组件而言这个很简单,使用keep-alive就可以缓存,但是多个视图同一个组件的时候似乎是不一样的)

新手提问,请各位高手不吝赐教。

1.使用Vue动态组件:

// 动态视图
<component :is="currentView" keep-alive></component>
// 组件定义
var ItemView = Vue.component('ItemView', {
    template: '<div><span>{{name}}</span><input v-model="name" /></div>',
    data: function(){
        return {
            name: 'test'
        }
    },
    created: function () {
      console.log('created test');
    }
})
// 注册视图
components: {
    hot: ItemView ,
    new: ItemView
}

这种方式下,我在输入框内修改了name的值,切换视图时发现另一个的name也修改了。
我认为这说明了切换的是同一个实例,但我预期效果是两个实例,其data是两个孤立作用域。。

2.使用vue-router

// 路由映射
'/hot': {
    name: 'hot',
    component: require('ItemView.vue')
},
'/new': {
    name: 'new'
    component: require('ItemView.vue')
}
// ItemView.vue
data() {
    return {
        name: ''
    }
},
route: {
   activate({next}){
       console.log('activate');
       this.pno = this.$route.name;
       next();
   },
   data({next}){
       console.log(this.name);
       next();
   }
}

router方式下,切换路由是发现,activate只执行一次,data钩子输出的name都是第一次进入的路由名,在设置canReuse以后,activate每次都执行,输出正常。

但给我的感觉就是一个组件在切,每次在钩子里更改了数据。

但我希望是每个视图对应一个新的实例。

阅读 11.5k
6 个回答

碰到了同样的问题,所以告诉你我的解决办法
在路由里配置component的时候使用extends, 或者使用es6的解构

import comp1 from './comp1'

routes = [
    {
        name: 'comp1',
        component: {extends:comp1}
    },
    {
        name: 'comp2',
        // 使用解构实现
        component: {...comp1}
    }
]

也有尝试使用下面创建实例的方法,但是行不通

const View = Vue.extend(comp1)
...
component: new View()
...

不是很懂你说的:

我希望保留每一个页面的dom和data

Vue建议的是数据去驱动组件,视图也是组件,所以正确的想法应该是数据去驱动视图的变化。如果你想想有你所说的动态视图,你可以用动态路径去做,在视图内部根据路径的分类来显示相关的数据:

// 路由设置
// 两种类型:hot和new
'/:type/app': {
   component: require('appView.vue')
}

然后你在appView里面根据params里面的type字段来确定是哪个视图,然后用哪一份数据。

新手上路,请多包涵

有些场景并不希望由数据重新驱动组件进行重新渲染。

例如我有一个仪表盘组件,一个仪表盘里面包含 n 个图表。我可能有多个仪表盘,如果使用数据驱动组件的话,我每次切换仪表盘时,都会造成仪表盘组件重新渲染,这就造成我的仪表盘切换其实很不流畅。

而且,如果由数据重新驱动,也就意味着我可能还要维护仪表盘内部的一些数据(例如仪表盘组件内部有筛选按钮)。

在这种情况下,我更希望是可以针对每一份仪表盘数据,生成一个新的仪表盘组件实例,然后我在各个实例之间进行切换。

刚找到了解决方案!!!!

    <keep-alive>
      <router-view :key="key"></router-view>
    </keep-alive>
computed: {
      // 默认情况下不同路由引入同一个组件 不触发created 数据作用域是同一个,加一个可以加以区别。
      key() {
        return this.$route.name !== undefined ? this.$route.name : this.$route
      }
    }
新手上路,请多包涵

单例组件?

var list = []
export default {
data(){
 return {
  list: list
 }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题