【问题标题】:vue.js cannot use data property in computed methodvue.js 不能在计算方法中使用数据属性
【发布时间】:2021-04-18 07:08:26
【问题描述】:

我正在尝试在这样的计算方法中使用我的数据属性:

data() {
    return {
      ToDoItems: [
        { id: uniqueId("todo-"), label: "Learn Vue", done: false },
        {
          id: uniqueId("todo-"),
          label: "Create a Vue project with the CLI",
          done: true,
        },
        { id: uniqueId("todo-"), label: "Have fun", done: true },
        { id: uniqueId("todo-"), label: "Create a to-do list", done: false },
      ],
    };
  },
computed: {
listSummary() {
  const numberFinishedItems = this.ToDoItems.filter((item) => item.done)
    .length;
  return `${numberFinishedItems} out of ${this.ToDoItems.length} items completed`;
},
},

但是IDE(Visual Studio Code)和编译器会报错:

类型“ComponentPublicInstance>'。

我正在关注 mozilla (https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties#adding_a_summary_counter) 的 vue.js 教程,但使用的是 v3。

有什么改变不再可能/不同了吗?

提前致谢

完整代码:

<template>
  <div id="app">
    <h1>To-Do List</h1>
    <to-do-form @todo-added="addToDo"></to-do-form>
    <h2 id="list-summary">{{ listSummary }}</h2>
    <ul aria-labelledby="list-summary" class="stack-large">
      <li v-for="item in ToDoItems" :key="item.id">
        <to-do-item :label="item.label" :done="true" :id="item.id"></to-do-item>
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import uniqueId from "lodash.uniqueid";
import { defineComponent } from "vue";
import ToDoItem from "./components/ToDoItem.vue";
import ToDoForm from "./components/ToDoForm.vue";

export default defineComponent({
  name: "App",
  components: {
    ToDoItem,
    ToDoForm,
  },
  data() {
    return {
      ToDoItems: [
        { id: uniqueId("todo-"), label: "Learn Vue", done: false },
        {
          id: uniqueId("todo-"),
          label: "Create a Vue project with the CLI",
          done: true,
        },
        { id: uniqueId("todo-"), label: "Have fun", done: true },
        { id: uniqueId("todo-"), label: "Create a to-do list", done: false },
      ],
    };
  },
  methods: {
    addToDo(toDoLabel: string) {
      this.ToDoItems.push({
        id: uniqueId("todo-"),
        label: toDoLabel,
        done: false,
      });
    },
  },
  computed: {
    listSummary() {
      const numberFinishedItems = this.ToDoItems.filter((item) => item.done)
        .length;
      return `${numberFinishedItems} out of ${this.ToDoItems.length} items completed`;
    },
  },
});
</script>

<style>
/* Global styles */
.btn {
  padding: 0.8rem 1rem 0.7rem;
  border: 0.2rem solid #4d4d4d;
  cursor: pointer;
  text-transform: capitalize;
}
.btn__danger {
  color: #fff;
  background-color: #ca3c3c;
  border-color: #bd2130;
}
.btn__filter {
  border-color: lightgrey;
}
.btn__danger:focus {
  outline-color: #c82333;
}
.btn__primary {
  color: #fff;
  background-color: #000;
}
.btn-group {
  display: flex;
  justify-content: space-between;
}
.btn-group > * {
  flex: 1 1 auto;
}
.btn-group > * + * {
  margin-left: 0.8rem;
}
.label-wrapper {
  margin: 0;
  flex: 0 0 100%;
  text-align: center;
}
[class*="__lg"] {
  display: inline-block;
  width: 100%;
  font-size: 1.9rem;
}
[class*="__lg"]:not(:last-child) {
  margin-bottom: 1rem;
}
@media screen and (min-width: 620px) {
  [class*="__lg"] {
    font-size: 2.4rem;
  }
}
.visually-hidden {
  position: absolute;
  height: 1px;
  width: 1px;
  overflow: hidden;
  clip: rect(1px 1px 1px 1px);
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: rect(1px, 1px, 1px, 1px);
  white-space: nowrap;
}
[class*="stack"] > * {
  margin-top: 0;
  margin-bottom: 0;
}
.stack-small > * + * {
  margin-top: 1.25rem;
}
.stack-large > * + * {
  margin-top: 2.5rem;
}
@media screen and (min-width: 550px) {
  .stack-small > * + * {
    margin-top: 1.4rem;
  }
  .stack-large > * + * {
    margin-top: 2.8rem;
  }
}
/* End global styles */
#app {
  background: #fff;
  margin: 2rem 0 4rem 0;
  padding: 1rem;
  padding-top: 0;
  position: relative;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
}
@media screen and (min-width: 550px) {
  #app {
    padding: 4rem;
  }
}
#app > * {
  max-width: 50rem;
  margin-left: auto;
  margin-right: auto;
}
#app > form {
  max-width: 100%;
}
#app h1 {
  display: block;
  min-width: 100%;
  width: 100%;
  text-align: center;
  margin: 0;
  margin-bottom: 1rem;
}
</style>

【问题讨论】:

    标签: javascript typescript vue.js vuejs3


    【解决方案1】:

    要在组件中进行类型推断,您应该使用 defineComponent 函数创建它:

    import {defineComponent} from 'vue';
    
    export default defineComponent({
     data() {
        return {
          ToDoItems: [
            { id: uniqueId("todo-"), label: "Learn Vue", done: false },
            {
              id: uniqueId("todo-"),
              label: "Create a Vue project with the CLI",
              done: true,
            },
            { id: uniqueId("todo-"), label: "Have fun", done: true },
            { id: uniqueId("todo-"), label: "Create a to-do list", done: false },
          ],
        };
      },
    computed: {
      listSummary() {
          const numberFinishedItems = this.ToDoItems.filter((item) => item.done)
             .length;
            return `${numberFinishedItems} out of ${this.ToDoItems.length} items completed`;
       },
    },
    
    })
    

    【讨论】:

    • 谢谢,据我所知,我已经这样做了。我已经在编辑中添加了整个代码
    • 你是如何创建项目的?
    • 使用 cli vue create
    • src 文件夹中有shims-vue.d.ts 文件吗
    • 我已经使用 TS 使用 vue cli 创建了这个project,并且这个错误只有在我错过使用defineComponent时才会出现
    【解决方案2】:

    也许你应该尝试注释计算的返回值

    查看 vue3 文档Annotating Return Types

    【讨论】:

      猜你喜欢
      • 2021-06-04
      • 2017-06-11
      • 2021-06-28
      • 2018-03-02
      • 2021-07-27
      • 2017-11-09
      • 1970-01-01
      • 2020-11-26
      • 2016-04-05
      相关资源
      最近更新 更多