vue-todo应用

image.png

开始第一步

components文件夹里新建五个vue文件

  • header.vue//头部组件 也就是图中的jtodo这个几个字
  • footer.vue//底部组件,就是下面的 ‘written by 懒人漫游’
  • todo.vue // 整个todo应用
  • tabs.vue //列表,这个是循环出来的
  • item.vue //按钮的功能

App.vue:注册组件


image.png

注意:由于只是演示代码,所以是在app里注册,正确的应该是通过路由注册,写在 router/index.js这个文件里

子组件注册:这个写在todo.vue里


image.png

正式开始写代码

先来todo.vue

<section class="real-app">
     <input 
        type="text"
        class="add-input"
        autofocus="autofocus"  
        placeholder="接下来做什么"
        @keyup.enter="addTodo"  
        >
      <Item/>
      <Tabs/>
    </section>  
    <script>
    import Item from './item.vue'
    import Tabs from './tabs.vue'
    import '../assets/styles/todo.styl'
    let id = 0
    export default {
        data() {
            return {
                todos:{
                  id:0,
                  content:'this is todo',
                  completed:false
                },
                filter:"all"
            }
        },
      components: {
          Item,
          Tabs
      },
      computed:{
          filteredTodos(){
          },
      },
      methods: {
         addTodo(e){
         },
         deleteTodo(id){
         },
         toggleFilter(state){
         },
         clearAllCompleted(){
         }
      },
    }
    </script> 

autofocus="autofocus" 一进来自动选中输入框

@keyup.enter="addTodo" 等同与v-on:key="addTodo"  

.enter是修饰符,注意是 '.enter' !,监听键盘事件,回车是enter,


image.png

现在来写item.vue

 <div :class="['todo-item',todo.completed ? 'completed' :'' ]">
        <input 
        type="checkbox"
        class="toggle"
        v-model="todo.completed"
        >
        <label> {{todo.content}}</label>
        <button class="destroy" @click="deletetodo"> </button>
    </div>
<script>
export default {
  props: {
      todo: {
          type: Object,
          required: true
      }
  },
  methods : {
      deletetodo(){     
      }
  }
}
</script>

:class="['todo-item',todo.completed ? 'completed' :'' ]" class的动态写法
v-model="todo.completed" //双向数据绑定
<label> {{todo.content}}</label>// 就是你写入的todo的内容
<button class="destroy" @click="deletetodo"> </button>//后面删除按钮

props:通过 Prop 向子组件传递数据,todo相对于item.vue来说是父组件,所以用props来传递数据

$emit 方法并传入事件的名字,来向父级组件触发一个事件

@click="deletetodo"是简写,deletetodo事件函数名

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

现在来写tabs.vue

    <div class="helper">
        <span class="left">2 items left</span>
        <span class="tabs">
            <span 
                v-for="state in states"
                :key="state"
                :class="[state,filter === state ? 'actived' :'']"
                @click="toggleFilter(state)"
            >
                {{state}}
            </span>
        </span>
        <span class="clear" @click="clearAllCompleted()">
            Clear completed
        </span>
    </div>
<script>
export default {
    props:{
        filter:{
            type:String,
            required:true,
        },
        todos: {
           type:Array,
           required: true,
        }
      },
      data(){
          return {
              states:['all','active','completed']
          }
      },
      methods:{
          toggleFilter(state){ 
          },
          clearAllCompleted(){
          }
       }
   }
</script>

这个组件主要就是
:class="[state,filter === state ? 'actived' :'']"能不能看懂
给class设置两个类名,如果filter === state,class ="state actived"
否则就是class ="state",这个和jquery一样,动态添加'active'

v-for="state in states" 
:key="state"

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 track-by="$index" 。
这个默认的模式是有效的,但是只适用于不依赖子组件状态或临时 DOM 状态(例如:表单输入值)的列表渲染输出。

:key 总的来说就是,可以提高性能

image.png

当你写完的时候,页面是这个样子(css部分请到时候查看源码)

开始第二步:实现业务逻辑

todo.vue

<script>
import Item from './item.vue'
import Tabs from './tabs.vue'
import '../assets/styles/todo.styl'
let id = 0
export default {
    data() {
        return {
            todos:[],
            filter:"all"
        }
    },
  components: {
      Item,
      Tabs
  },
  computed:{
      filteredTodos(){
          if (this.filter === 'all'){
              return this.todos
          }
          const completed = this.filter === 'completed'
          return this.todos.filter(todo => completed ===todo.completed)
      },

  },
  methods: {
      addTodo(e){
         if(e.target.value==''){
             alert("你什么都没有添加!")
         }
         else{
             this.todos.unshift({
              id:id++,
              content: e.target.value.trim(),
              completed:false
          }),
          e.target.value =''
         }     
      },
     deleteTodo(id){
        //  console.log(todo => todo.id ===id);
         this.todos.splice(this.todos.findIndex(todo => todo.id ===id),1)
     },
     toggleFilter(state){
         this.filter =state
     },
     clearAllCompleted(){
         this.todos = this.todos.filter(todo => !todo.completed)
         
     }
  },
}
</script>
  • data()里的todos要改成空数组,在增加的时候,添加进去就可以了
  • 改写<Item/> <Tabs/>
 <Item 
  :todo="todo"
  v-for="todo in filteredTodos"
  :key="todo.id"
  @del="deleteTodo"
></Item>   
<Tabs 
  :filter="filter" 
  :todos="todos"
  @toggle="toggleFilter"
  @clearAll="clearAllCompleted"
></Tabs>

@del="deleteTodo"是子组件传过来的,写在父组件的好处是方便解耦。

  • 实现addTodo(e),在todo列表的最上面添加todo,id从0开始,每次添加,id++,内容就是每次input输入的值然后去掉空格,完了之后要把input的内容清空,所以是e.target.value =''

  • 删除deleteTodo(id),找到对应的下标,删除一个

  • 切换状态toggleFilter(state) :

this.filter =state
  • 清除完成的clearAllCompleted():
this.todos = this.todos.filter(todo => !todo.completed)

然后实现items.vue的业务逻辑

 methods : {
      deletetodo(){
          this.$emit("del",this.todo.id);
      }
  }

最后是tabs.vue的

computed: {
        unFinishedTodoLength() {   //计算left的items的长度
            return (this.todos.filter(todo => !todo.completed).length)
        }
    },
    data() {
        return {
            states: ['all', 'active', 'completed']
        }
    },
    methods: {
        toggleFilter(state) {
            this.$emit('toggle', state)
        },
        clearAllCompleted() {
            this.$emit('clearAll')
        }
    }

把html部分改写下,动态显示未完成的数字显示

<span class="left">{{unFinishedTodoLength}} items left</span>

写完todo应用之后对组件注册,事件处理函数,vue的相关指令,父子组件的通信有了进一步的了解,对vue使用有了更多的经验

源码
本文所写代码 来自慕课网

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容