繁体   English   中英

无法在带有 typescript 的 vue 中使用 Mixins

[英]unable to use Mixins in vue with typescript

我有这样的文件夹结构

--Page    
   -group.vue    
--Services
  -groupMixin.ts

group.vue脚本

<script lang="ts">
     import { Vue, Component, Mixins } from 'vue-property-decorator'

     import { GroupMixin } from '../../services/groupMixin';
     @Component
     export default class Group extends Mixins(GroupMixin) {
        created () {
          console.log(this.test)
        }
      }
</script>

groupMixin.ts代码

import { Vue } from 'vue-property-decorator'
//creating mixins.
export class GroupMixin extends Vue {
  test: string = 'sss'
}

我在这里面临两个问题。

首先,要导入我使用的 ts 文件../../,有没有办法使用 ./ 或 @/。 在不使用 lang="ts" 的情况下,我可以导入这样的 js 文件 @/services/...

其次,无法访问我在 groupmixin.ts 中声明的变量测试

今天我花了很多时间试图弄清楚如何让 Vue mixin 在 TypeScript 项目中工作。 显然,教程中所说的使用 mixin 的所有正常方法在 TypeScript 中都不起作用。 组件无法访问在其 mixin 中定义的属性,因为 Vue 框架的 mixin 代码显然不是 TypeScript 友好的。

最终,我确实找到了一种在 TypeScript 中使用 mixin 的方法。 事实上,工作得很好。 我的项目中有多个级别的 mixin 继承,mixin 扩展了其他 mixin,并且一切都按照我的预期工作。 秘诀是我必须安装这个第三方包,这是有人写的来修复 TypeScript 中的 mixin:

https://www.npmjs.com/package/vue-typed-mixins

几个警告(但都不是什么大问题):

  1. 这个插件只适用于我在 .ts 文件而不是 .vue 文件中定义我的 mixins 的情况。 这对我来说不是问题,因为我的 mixins 只包含代码,没有 html 或 css(而且我想不出有什么意义的情况)。

  2. 当您在组件中包含 mixin 时,请确保按照与包网站上的示例(上面的 url)相同的方式进行操作。 如果您只是安装软件包而不重构您的代码以遵循站点上的示例,则它将无法正常工作。

这是一个简单的例子:

// /src/mixins/MyMixin.ts

import Vue from "vue";

export default Vue.extend({
    data: function () {
        return {
            mixinMessage: "this came from MyMixin!"
        };
    },
    created: function () {
        console.log("MyMixin.created()");
    },
    mounted: function () {
        console.log("MyMixin.mounted()");
    },
    methods: {
        mixinOutput: function (text:string) {
            console.log("mixin says: " + text);
        }
    }
});

然后由以下人员使用:

// /src/components/MyComponent.vue

<template>
    <div>
        whatever
    </div>
</template>

<style>
    /* whatever */
</style>

<script lang="ts">
    import mixins from "vue-typed-mixins";
    import MyMixin from "../mixins/MyMixin";

    export default mixins(MyMixin).extend({
        created: function () {
            console.log("MyComponent.created()");
        },
        mounted: function () {
            console.log("MyComponent.mounted()");

            this.mixinOutput("hello from MyComponent");
            this.mixinOutput(this.mixinMessage);
        }
    });
</script>

请尝试执行以下操作以使您的 mixin 工作:

组.vue

<script lang="ts">
 import Vue from 'vue';
 // mixins only exist in `vue-class-component` and Component is a default export.
 import Component, { mixins } from 'vue-class-component';

 import { GroupMixin } from '../Services/groupMixin';

 @Component
 export default class Group extends mixins(GroupMixin) {
    created () {
      console.log(this.test)
    }
  }
</script>

groupMixin.ts

import { Vue } from 'vue'

export class GroupMixin extends Vue {
  test: string = 'sss'
}

还有一个原因,我现在用进口Vue使用import Vue from 'vue'; ,这主要是因为一些 IDE 在从vue-class-component导入时会突出显示像$emit这样的 Vue 函数。

至于导入 ts 文件,如果你不使用vue-cli你需要设置webpack 的解析别名,也在你的tsconfig.json ,可能需要使用tsconfig-paths

基于@Joe Irby 的回答,我发现它在没有 vue-typed-mixins 的情况下也能工作。

当你的 mixin 扩展了 Vue,你可以通过扩展你的 mixin 来创建你的组件:

// MyMixin.ts

import Vue from "vue";

export default Vue.extend({
    data: function () {
        return {
            message: "Message from MyMixin!"
        };
    }
});


// MyComponent.vue

<template>
    ...
</template>

<script lang="ts">
    import MyMixin from "@/mixins/MyMixin";

    export default MyMixin.extend({
        mounted: function () {
            console.log(this.message);
        }
    });
</script>

截至今天,有两种方法可以在 Typescript/Vue 中使用 mixin:

  1. 如果你的 mixin 只包含变量:
// mixins/title.ts
import { Vue, Component } from 'vue-property-decorator'

@Component
export default class titleMixin extends Vue {
  public test: string = 'Hello, hello, hello'
}

// Page.vue
import { Component, Vue, Mixins } from 'vue-property-decorator'
import titleMixin from '@/mixins/title'

export default class Page extends Mixins(titleMixin) {
  private mounted(): void {
    console.log(this.test) // would print: Hello, hello, hello
  }
}
  1. 如果您使用生命周期钩子:
// mixins/title.ts
import { Vue, Component } from 'vue-property-decorator'

@Component
export default class titleMixin extends Vue {
  private mounted(): void {
    console.log('somevalue')
  }
}

// Page.vue
import { Component, Vue } from 'vue-property-decorator'
import titleMixin from '@/mixins/title'

@Component({
  mixins: [titleMixin]
})
export default class Page extends Vue {} // this will print console.log

这样它对我有用。 你可以看看'vue-class-component'包: https : //github.com/vuejs/vue-class-component/blob/master/test/test.ts#L389

mixins.ts

import { Vue, Component } from "vue-property-decorator";

@Component
export default class Mixin extends Vue {
  public perfectScrollbarSetting: object = {
    maxScrollbarLength: 750
  };
  public widthClient: number = 0;
  public heightClient: number = 0;
}

文件关于.vue

<template>
</template>
<script lang="ts">
import { Vue, Component, Mixins } from "vue-property-decorator";
import { generalInfo } from "../../store/modules/general";
import Mixin from "../../mixin/mixins";
@Component({
  mixins: [Mixin]
})
export default class About extends Mixins(Mixin) {
  mounted() {
    console.log(this.widthClient) //it's work
  }

}
</script>

如果你不使用 vue-class-component(目前我不是因为它不能很好地与 setup/composition api 一起工作)你可以使用 defineComponent 作为 mixin,它可以在 vue 3 中使用 typescript

混入的例子:

yor_mixin.ts

import {defineComponent} from "vue"

interface MixinState{
    lastScrollPosition: number;
}

export default defineComponent({
    data(): MixinState{
        return {
            lastScrollPosition: 0,
        }
    },
    methods:{
        scrollDisable(){
            document.body.style.overflow = "hidden";
            this.lastScrollPosition = window.pageYOffset;
        },
        scrollEnable(){
            document.body.style.overflow = "auto";
            window.scrollTo(0, this.lastScrollPosition)
        }
    }
})

和组件


<script lang="ts">
import {computed, defineComponent} from 'vue';
import {useStore, MUTATIONS} from "@/store";
import scrollDisableMixin from "@/mixins/scrollDisable";

export default defineComponent({
  mixins: [scrollDisableMixin],

  setup(){
    const store = useStore();
    return {
      expanded: computed(() => store.state.menu.expanded),
      toggle: () => store.commit(MUTATIONS.TOGGLE_MENU_MAIN),
    }
  },

  watch: {
    expanded: function(){
      this.expanded ? this.scrollDisable() :this.scrollEnable();
    }
  }

})

作为 mixins 的缺点,为什么不尝试对 Vue3 的设置进行 mixin 重构: https ://codesandbox.io/s/delicate-sea-0xmim?file =/ src/components/HelloWorld.vue:2262-2495 Comp.视图

export default {
  name: "HelloWorld",
  setup() {
    const { test } = useGroup();
    console.log(test);
    return Object.assign({}, useGroup());
  },
  mounted() {
    this.compRef = this;
  },
  props: {
    msg: String,
  },
};

使用Group.js

import { ref, nextTick, onMounted } from "vue";

export default () => {
  const compRef = ref(null);
  const test = "Hello World!";

  onMounted(() => {
    nextTick(() => {
      if (compRef.value) {
        const vm = compRef.value;
        console.log(vm.$el, vm.msg);
      }
    });
  });
  return {
    test,
    compRef
  };
};

这个答案是为那些愿意使用vue-class-component (decorators) 的人准备的……你要做的就是从 'vue-class-component' 导入Options并在那里添加你的 mixin。

脚步:

1- 创建你的 mixin:在这个例子中,我正在创建一个 mixin 来格式化时间 (HH:MM:ss)

//Mixin
 export default {
   methods: {
     formatTime(date: string) {
       return new Date(date)
         .toTimeString()
         .replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");
     },
   },
 };

2- 通过将其添加到 Option 装饰器中来使用组件中的 mixin。

   //Home.vue

    import { Options, Vue } from "vue-class-component";

    import formatTimeMixin from '../mixin/formatTime';

    <template>
       <h1> Time left: {{formatTime(timeLeft)}} </h1>
    </template>

    @Options({
      mixins: [formatTimeMixin],
    })
    export default class Home extends Vue {
       timeLeft = 10000;
    }

就是这样,希望这可以帮助那里的人!

我不会再认为这是一个“mixin”了,但是有效..

SortHelperMixin.ts

import Vue from "vue";
export default Vue.extend({
  methods: {
    sortDate(a: string, b: string): number {
       ...
    },
  }
})

我的组件.vue

import SortHelperMixin from '@/mixins/SortHelperMixin'
export default Vue.extend({
  name: "MyComponent",
  data() {
    return {
      sortHelperMixin: new SortHelperMixin(),
    };
  },
})

利用

this.sortHelperMixin.sortDate(a, b)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM