如何在 Vue-cli 中使用 props、$ref 和 $emit?

Posted

技术标签:

【中文标题】如何在 Vue-cli 中使用 props、$ref 和 $emit?【英文标题】:How can I use props, $ref and $emit in Vue-cli? 【发布时间】:2020-09-19 04:39:47 【问题描述】:

我一直在用 Vue-cli 学习 Vuejs。

我正在尝试弄清楚 props$emit 是如何工作的。

我想不通的一件事是如何处理与多个组件相关的function

All,Ongoing,Done 按钮应该根据每个复选框值过滤列表,并且在激活时其颜色变为绿色。

我不知道把filteredTodos() 的东西放在哪里,目前我在ListTodo.vue 中添加了这些东西,因为它们在Swichers.vueListTodo.vue 中都相关。

我的代码是:Here

如果有人知道,你能告诉我怎么做吗?

谢谢

【问题讨论】:

我想你明白了!在 App 中取消注释您的 data 项目,并在 ListToDo 中取消注释 prop。剩下要做的就是将道具传递给 ListTodo...<ListToDo :filtered="filtered /> 另外,根据您在切换器中发出的内容,filtered 属性似乎应该是字符串,而不是对象。 感谢您的评论,我按照您的方式,需要添加 filterState: this.filtered 以逃避覆盖道具。但是,仍然没有解决。我更新了一个问题和代码。如果您不介意,请看一下。 【参考方案1】:

更符合 vuejs 的这种精神,避免 refs 和在子组件中具有状态。

应用程序包含项目和过滤器,todolist.vue 将道具绑定到过滤列表(计算属性)。 切换器在过滤器上采用 v-model(双向绑定)。 Remove all 作为回调属性传递。

(编辑)

App.vue

<template>
  <div>
    <h1>TODO</h1>
    <input type="text" v-model="inputTask" placeholder="Enter your task">
    <button @click="addTask">Add task</button>

    <Switchers
      v-model='filter'
      :onRemoveAll="removeAllItem"
    />
    <ListTodo :todos='filtered' :noTask='noTask' :onRemoveTask='removeTask' :onToggleStatus='toggleStatus' />
  </div>
</template>

<script>
import Switchers from "./components/Switchers";
import ListTodo from "./components/ListTodo";

export default 
  keyName: 'myTodoList',
  components: 
    Switchers,
    ListTodo,
  ,

  created() 
    let keyObject =JSON.parse(localStorage.getItem(this.keyName))
    if (keyObject) 
      this.todos = keyObject;
    
  ,
  data() 
    return 
      inputTask: '',
      // filtered:'',
      filter: 'all',


      todos: [],
    ;
  ,
  computed: 
    filtered() 
      this.filter; this.todos;
      return this.filteredTodos()
    ,
    id()  return this.todos.length+1 ,
    noTask() 
      return 
        'all': 'No tasks',
        'ongoing': 'No ongoing tasks',
        'done': 'No done tasks',
      [this.filter]
    ,
  ,
  methods: 
    addTask() 
      if (this.inputTask==='') 
        return
      
      this.addTaskChild(this.inputTask);
      this.inputTask=''
    ,
    addTaskChild(inputValue) 
      const todo = id: this.id, task:inputValue, done:false
      this.todos.push(todo)
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
      this.filter = 'all'
    ,

    removeAllItem() 
      this.todos = []
      localStorage.clear();
      this.filter = 'all'
    ,

    filteredTodos() 
      return this.todos.filter(todo => 
        if (this.filter === 'ongoing') 
          return !todo.done;
         else if (this.filter === 'done') 
          return todo.done;
         else 
          return true;
        
      );
    ,

    toggleStatus(todo) 
      todo.done =  !todo.done
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
    ,

    removeTask(t) 
      this.todos = this.todos.filter(todo => todo.id !== t.id)
    ,
  
;
</script>


ListTodo.vue

<template>
  <div>
    <p>todos.length tasks left /  todos.length tasks of all</p>
    <ul>
      <li v-for="todo in todos" :class="done:todo.done" :key="todo.id">
      <input type="checkbox" :checked="todo.done" @click="status(todo)">
       todo.task 
      <button @click="onRemoveTask(todo)">Remove task</button>
      </li>
    </ul>
    <p v-show="todos.length===0">noTask</p>
  </div>
</template>

<script>
export default 
  props: 
    todos: 
      type: Array,
      required: true
    ,
    onRemoveTask: 
      type: Function,
      required: true
    ,
    onToggleStatus: 
      type: Function,
      required: true
    ,
    noTask: 
      type: String,
      required: true
    
  ,
  data() 
    return 
      id: 1,
      done:false,
    ;
  ,
  methods: 
    status(todo) 
      this.onToggleStatus(todo)
    ,
  ,
;
</script>

Switchers.vue

<template>
  <div>
    <button :class="active: filter ==='all'" @click="set_filter('all')">All</button>
    <button :class="active: filter ==='ongoing'" @click="set_filter('ongoing')">Ongoing</button>
    <button :class="active: filter ==='done'" @click="set_filter('done')">Done</button>
    <button @click="onRemoveAll">Remove all</button>
  </div>
</template>
<script>
export default 
  props: 
    value: 
      type: String,
      required: true
    ,
    onRemoveAll: 
      type: Function,
      required: true
    
  ,
  watch: 
    value: 
      handler(v) 
        if (this.filter !== v)
          this.filter = v
        ,
      immediate: true
    
  ,
  data() 
    return 
      filter:'',
    ;
  ,
  methods: 
    set_filter(f) 
      this.filter = f
      this.$emit('input', f)
    ,
  ,
;
</script>
<style lang="scss" scoped>
.active background: turquoise;

</style>

惯用的 vuejs 更喜欢响应式属性而不是命令式风格。在这种情况下,我们宁愿保留一份待办事项列表 + 过滤条件(在 App 中),并公开下一个 id、过滤列表和 noTask 消息的计算属性。

Switchers 是一个纯控制器组件:它没有状态,唯一的作用是将用户选择转换为调用 App 模型。

ListTodo 是一个视图,只负责显示作为道具提供的待办事项列表。它不关心列表是否被过滤。

也可以进行一些小的样式更改,但它们与 vuejs/emit 没有任何关系,所以我没有这样做。

Sandbox

【讨论】:

感谢您的评论,我是 Vue 的初学者。以我的毛孔经验,我无法想象你说什么:(我会多练习! 我用完整的源代码编辑了我的答案。希望能帮助到你。祝你好运! 非常感谢您的回答和描述。仍然需要一些时间来了解它们如何根据您的代码相互连接。无论如何,我会弄清楚谢谢,我很感激。

以上是关于如何在 Vue-cli 中使用 props、$ref 和 $emit?的主要内容,如果未能解决你的问题,请参考以下文章

如何将html中父组件的prop传递给组件vue

Vue-Cli使用路由

安卓手机找不到build.prop 在系统内部储存的system中只有两个文件夹,,

使用nodeJs安装Vue-cli

vue-cli中 components插件的应用

(ESLint) 未找到规则“re​​act/jsx-sort-prop-types”的定义