Vue todos案例

文章目录

          • todos案例
            • 1 提供的数据和 HTML结构
            • 2 把数据渲染到页面上
            • 3 把类名是 new-todo 按回车键的时候 把输入框中的数据展示到页面上
            • 4. 实现全选功能
            • 5 实现删除功能
            • 6 实现编辑功能
            • 7 Clear completed
            • 8 number item left
          • todos案例-组件化抽离
            • 1 提供的数据和 HTML结构
            • 2 抽离头部组件
            • 3 抽离数据展示组件
            • 4 抽离fotter 部分
          • todos接口案例
            • 1 请求后台接口list 获取 数据展示到页面上
            • 2 增加内容
            • 3 双击修改列表信息
            • 5 删除全部完成
            • 6 实现全选功能

todos案例
1 提供的数据和 HTML结构
  • 引入todos的CSS样式 (HTML和 CSS 已经写好 我们需要改成Vue动态渲染的)
 
    <section id="todoapp" class="todoapp">
        <header class="header">
            <h1>todosh1>
            <input placeholder="What needs to be done?" class="new-todo">
        header>
        <section class="main">
            	<input id="toggle-all" type="checkbox" class="toggle-all"> 
            	<label for="toggle-all">Mark all as completelabel>
            <ul class="todo-list">
                <li class="">
                    <div class="view"><input type="checkbox" class="toggle"> 
                        <label>吃饭label> 
                        <button class="destroy">button>
                    div> 
                    <input class="edit">
                li>
                <li class="">
                    <div class="view">
                        <input type="checkbox" class="toggle">
                        <label>睡觉label> 
                        <button class="destroy">button>
                    div> <input class="edit">li>
                <li class="completed">
                    <div class="view">
                        <input type="checkbox" class="toggle"> 
                        <label>打豆豆label> 
                        <button class="destroy">
                        button>div> 
                    <input class="edit">
                li>
            ul>
        section>
        <footer class="footer">
            <span class="todo-count">
                <strong>2strong> item leftspan>
            <ul class="filters">
                <li><a href="#/" class="selected">Alla>li>
                <li><a href="#/active">Activea>li>
                <li><a href="#/completed">Completeda>li>
            ul> 
            <button class="clear-completed">Clear completedbutton>
        footer>
    section>




    <link rel="stylesheet" href="css/base.css">
    <link rel="stylesheet" href="css/index.css">



    <script>
        new Vue({
            el: "#todoapp",
            data: {
                todos: [{
                    id: 1,
                    title: '吃饭',
                    completed: false
                }, {
                    id: 2,
                    title: '睡觉',
                    completed: false
                }, {
                    id: 3,
                    title: '打豆豆',
                    completed: true
                }]
            }
        })
    script>
2 把数据渲染到页面上
  • 根据completeed 的状态动态给li 绑定类名
    • 未完成状态:不需要样式 完成状态: 类名为 completed 编辑状态:类名为 editing
    • 如果completed 为 true 则给当前li 添加 completed
<li v-for="(item, index) in todos"
    	v-bind:class="{completed: item.completed}"
    >
         <div class="view">
             <input type="checkbox" class="toggle"> 
             <label>{{item.title}}label> <button class="destroy">button>
    	div> 
    	<input class="edit">
li>
3 把类名是 new-todo 按回车键的时候 把输入框中的数据展示到页面上
    1. 获取文本框中用户输入的数据
    1. 判断数据是否非空 如果是空的,则什么都不做 如果不是空的,则添加到数组中
    1. 添加到数组中
    1. 清空文本框
<header class="header">
            <h1>todosh1>
            
            <input class="new-todo" placeholder="What needs to be done?" 				                 @keyup.enter="addTodo" >
header>
    <script>
        new Vue({
            el: "#todoapp",
            data: {
                todos: [{
                    id: 1,
                    title: '吃饭',
                    completed: false
                }, {
                    id: 2,
                    title: '睡觉',
                    completed: false
                }, {
                    id: 3,
                    title: '打豆豆',
                    completed: true
                }]
            },
            methods:{
                  addTodo(event) {
                    // 1. 获取文本框中用户输入的数据
                    var todoText = event.target.value.trim()
                    // 2. 判断数据是否非空
                    if (!todoText.length) {
                        return
                    }
					 // 3. 添加到数组中
                    const lastTodo = this.todos[this.todos.length - 1]
                    const id = lastTodo ? lastTodo.id + 1 : 1

                    // 3.1 当数组发生变化,则绑定渲染该数组的视图也会得到更新
                    this.todos.push({
                        id,
                        title: todoText,
                        completed: false
                    })

                    // 4. 清空文本框
                    event.target.value = ''
                },
            }
            }
        })
    script>

4. 实现全选功能
  • 4.1 当点击三角即类名为 toggle-all 的复选框的时候
    • 如果当前三角高亮 即 复选框为选中状态 让当前所有的li 为 完成状态
      • 通过双向绑定获取当前复选框的选中状态
    • 否则为未完成状态
  • 4.2 当点击单个li 里面的复选框的时候 如果当前复选框选中 则当前的状态为完成状态
    • 通过双向绑定获取当前复选框选中状态 通过选中状态动态改变 completed 的值
  • 4.3 如果当前所有的li 都处于完成状态 即 复选框都选中 则上面的 toggle-all 复选框选中 有一个没有选中则当前toggle-all 复选框 处于未选中状态
<section class="main">
    
    <input v-model="toggleStat"
           id="toggle-all" 
           type="checkbox" class="toggle-all">

    <ul class="todo-list">
                <li v-for="(item, index) in todos" 
                    v-bind:class="{completed: item.completed}">
                    <div class="view">
                            
                        <input type="checkbox" class="toggle" v-model="item.completed">
                        <label>{{item.title}}label>
                        <button class="destroy">button>
                    div>
                    <input class="edit">
                li>
            ul>
section>       
  <script>
        new Vue({
            el: "#todoapp",
            methods: {
                addTodo(event) {
               
                },
                   // 删除任务项
                removeTodo(delIndex, event) {
                    this.todos.splice(delIndex, 1)
                },
            },
            computed: {
                toggleStat: {
                    /*
                    	当读取一个变量的时候会触发该变量的getter
                    	当修改该变量时候会触发他的setter.
                    
                    */
                    get() {
                        // 4.3 4.3  如果当前所有的li 都处于完成状态 即 复选框都选中 则上面的  toggle-all  复选框选中 有一个没有选中则当前toggle-all  复选框  处于未选中状态
                        return this.todos.every(item => item.completed)
                    },
                    //  当复选框为选中的时候当前  传入的为 true  没有选中传入的为false 
                    set(val) {
                        this.todos.forEach(todo => todo.completed = val)
                    }
                }
            }
        })
    script>
5 实现删除功能
  • 给类名是 destroy 的按钮添加点击事件
  • 点击当前按钮 删除当前按钮所在的 li
 <section class="main">
            <input v-model="toggleStat" id="toggle-all" type="checkbox" 
                   class="toggle-all">
            <label for="toggle-all">Mark all as completelabel>
            <ul class="todo-list">

                <li v-for="(item, index) in todos" 
                    v-bind:class="{completed: item.completed}">
                    <div class="view">
                        <input type="checkbox" class="toggle" v-model="item.completed">
                        <label>{{item.title}}label>
                        
                        <button class="destroy" 
                                @click="removeTodo(index)">
                        button>
                    div>
                    <input class="edit">
                li>
            ul>
        section>
  <script>
        new Vue({
            el: "#todoapp",
            methods: {
                addTodo(event) {
               
                },
                 // 删除任务项
                removeTodo(delIndex) {
                    this.todos.splice(delIndex, 1)
                },
            },

        })
    script>
6 实现编辑功能
  • 6.1 双击标题的时候 当前li 的类名添加 editing
    • 6.1.1 给当前标题添加双击事件
    • 6.1.2 给当前li 添加editing 添加editing后 当前隐藏的输入框会显示出来
  • 6.2 输入框的默认值为当前标题
  • 6.3 当用户没有编辑 的时候 按esc退出的时候 数据不发生变化
  • 6.4 当用户输入内容按回车键的时候 把标题更新
  • 6.5当用户失去焦点的 时候 把输入框中的标题更新
<section class="main">
            <input v-model="toggleStat" id="toggle-all" type="checkbox" 
                   class="toggle-all">
            <label for="toggle-all">Mark all as completelabel>
            <ul class="todo-list">
				
                <li v-for="(item, index) in todos" 
                  v-bind:class="{completed: item.completed, editing: item === currentEditing}">
                    <div class="view">
                        <input type="checkbox" class="toggle" v-model="item.completed">
                         
                        <label
                                 @dblclick="currentEditing = item"
                               >{{item.title}}label>
                  
                        <button class="destroy" 
                                @click="removeTodo(index)">
                        button>
                    div>
                    
                    <input class="edit" 
                           :value="item.title"
                            @keyup.esc="currentEditing = null"
                            @keyup.enter="saveEdit(item, index, $event)"
                            @blur="saveEdit(item, index, $event)"

                           >
                li>
            ul>
        section>

  <script>
        new Vue({
            el: "#todoapp",
            data: {
                // 6.1.2  标识符默认的为空即一开始加载的时候类名 editing  不加载
                currentEditing: null,
            },
            methods:{
                 // 保存编辑项
                saveEdit(item, index, event) {
                    // 1. 拿到文本框中的数据
                    //    非空校验
                    //    如果为空,则直接删除这个 item
                    //    如果不为空,则修改任务项的 title 数据
                    var editText = event.target.value.trim()

                    // 程序员要具有工匠精神:优化简写
                    // !editText.length ?
                    //   this.todos.splice(index, 1) :
                    //   item.title = editText

                    if (!editText.length) {
                        // 将元素直接从数组中移除
                        return this.todos.splice(index, 1)
                    }

                    // 2. 将数据设置到任务项中
                    item.title = editText

                    // 3. 去除 editing 样式
                    this.currentEditing = null
                },
            }
        })
    script>
7 Clear completed
  • 点击Clear completed 的时候删除所有的 已完成项
 <footer class="footer">
     
        <button
          class="clear-completed"
          @click="removeAllDone">Clear completedbutton>
     footer>
  <script>
        new Vue({
            el: "#todoapp",
            data: {
                // 6.1.2  标识符默认的为空即一开始加载的时候类名 editing  不加载
                currentEditing: null,
            },
            methods:{
               
   // 删除所有已完成任务项
      removeAllDone() {
        // 找到所有已完成的任务项,把其删除。错误的写法
        // this.todos.forEach((item, index) => {
        //   if (item.completed) {
        //     // 已完成
        //     console.log(item.title)
        //     this.todos.splice(index, 1)
        //   }
        // })

        // 把所有需要保留的数据过滤出来,然后重新赋值给 todos
        this.todos = this.todos.filter(item => !item.completed)

        // 如果想要就在遍历的过程去删除,则可以使用 for 循环
        // 没删除一个,我们可以控制让索引 --
        // for (let i = 0; i < this.todos.length; i++) {
        //   if (this.todos[i].completed) {
        //     this.todos.splice(i, 1)
        //     i--
        //   }
        // }
      },
            }
        })
    script>

8 number item left
  • 通过计算属性检测当前complete未完成的状态
<span class="todo-count"><strong>{{leftCount}}strong> item leftspan>
  <script>
        new Vue({
            computed: {

                leftCount: function() {
                    return this.todos.filter(item => !item.completed).length
                }
            }
        })
    script>
todos案例-组件化抽离
1 提供的数据和 HTML结构
  • 引入todos的CSS样式 (HTML和 CSS 已经写好 我们需要改成Vue动态渲染的)
 
    <section id="todoapp" class="todoapp">
        <header class="header">
            <h1>todosh1>
            <input placeholder="What needs to be done?" class="new-todo">
        header>
        <section class="main">
            	<input id="toggle-all" type="checkbox" class="toggle-all"> 
            	<label for="toggle-all">Mark all as completelabel>
            <ul class="todo-list">
                <li class="">
                    <div class="view"><input type="checkbox" class="toggle"> 
                        <label>吃饭label> 
                        <button class="destroy">button>
                    div> 
                    <input class="edit">
                li>
                <li class="">
                    <div class="view">
                        <input type="checkbox" class="toggle">
                        <label>睡觉label> 
                        <button class="destroy">button>
                    div> <input class="edit">li>
                <li class="completed">
                    <div class="view">
                        <input type="checkbox" class="toggle"> 
                        <label>打豆豆label> 
                        <button class="destroy">
                        button>div> 
                    <input class="edit">
                li>
            ul>
        section>
        <footer class="footer">
            <span class="todo-count">
                <strong>2strong> item leftspan>
            <ul class="filters">
                <li><a href="#/" class="selected">Alla>li>
                <li><a href="#/active">Activea>li>
                <li><a href="#/completed">Completeda>li>
            ul> 
            <button class="clear-completed">Clear completedbutton>
        footer>
    section>




    <link rel="stylesheet" href="css/base.css">
    <link rel="stylesheet" href="css/index.css">



    <script>
        new Vue({
            el: "#todoapp",
            data: {
                todos: [{
                    id: 1,
                    title: '吃饭',
                    completed: false
                }, {
                    id: 2,
                    title: '睡觉',
                    completed: false
                }, {
                    id: 3,
                    title: '打豆豆',
                    completed: true
                }]
            }
        })
    script>
2 抽离头部组件
  • 把头部封装到一个组件中
  • 给输入框绑定事件
  • 当用户输入完数据后 通过子向父传值 把获取的用户输入的信息提交到父组件中去
  • 父组件接收到子组件传递的数据 存放到todos 中
  • 父组件中展示头部组件
<section id="todoapp" class="todoapp">
      	
        <myheader @inpvalue="addTodo">myheader>

   section>

<script>
     //   1、把header  部分提取出来 
        var myheader = {
                template: `
                

todos

`
, methods: { //1.1 把用户输入的数据传递到父组件中去 addToParent(event) { var todoText = event.target.value.trim() if (!todoText.length) { return } this.$emit("inpvalue", todoText) } } } new Vue({ el: "#todoapp", data: { currentEditing: null, todos: [{ id: 1, title: '吃饭', completed: false }, { id: 2, title: '睡觉', completed: false }, { id: 3, title: '打豆豆', completed: true }] }, methods: { addTodo(todoText) { # 2.4 父组件接收到子组件传递的数据 存放到todos 中 const lastTodo = this.todos[this.todos.length - 1] const id = lastTodo ? lastTodo.id + 1 : 1 //当数组发生变化,则绑定渲染该数组的视图也会得到更新 this.todos.push({ id, title: todoText, completed: false }) // 清空文本框 event.target.value = '' }, } # 2.1 注册子组件 components: { myheader } })
script>
3 抽离数据展示组件
  • 3.1 把显示数据的代码封装到一个组件中
  • 3.2 把父组件中的todos 传递过来 子组件接收到父组件传递过来的数据 进行渲染
  • 3.3 点击删除 删除当前的数据
  • 3.4 双击的时候 当前数据可编辑
  • 3.5 按enter键的时候 保存当前数据
  • 3.6 实现全选功能
 <section id="todoapp" class="todoapp">
     
     
     
     
     <mylist :todos="todos" @dbl-click="aaaa" 
             @removetodo="removeTodo"
             @save-edit="saveEdit" 
             :currentediting="currentEditing" 
             >
     mylist>

 section>
 <script src="js/vue.js">script>

 <script>
     var mylist = {
         # 3.2.2   子组件通过 props 接收父组件传递过来的数据
         props: ["todos", "currentediting"],
         template: ` 
         
# 3.6 实现全选功能 通过双向绑定 计算属性 toggleStat1
    # 3.2.3 把todos 展示到当前页面
  • # 3.4 双击的时候 当前数据可编辑 # 3.4.1 添加双击事件 我们通过 类名 editing 来控制当前输入框显示 # 在父组件中定义一个标识符 currentEditing 默认为 空 当我们双击的时候 # 给当前点击的li 添加 editing 类名 #3.3 点击删除 删除当前的数据 #3.3.1 给按钮绑定事件 需要把当前的id 传入过来
    # 3.5 按enter键的时候 保存当前数据
`
, methods: { # 3.3.2 删除操作 子组件不要操作父组件里面的数据 把对应的数据传递到父组件中 removeTodoParent(index) { this.$emit("removetodo", index) }, # 3.5.1 把当前数据发送到父元素 通过父元素保存子元素数据 saveEdit(item, index, event) { var editText = event.target.value.trim() this.$emit("save-edit", editText, item, index) }, # 3.4.2 子组件 把当前点击的li 传递到父元素 doubleMethods(item) { this.$emit("dbl-click", item) } }, computed: { # 3.6.1 实现全选功能 toggleStat1: { get() { return this.todos.every(item => item.completed) }, set(val) { this.todos.forEach(todo => todo.completed = val) } }, }, } new Vue({ el: "#todoapp", data: { currentEditing: null, todos: [{ id: 1, title: '吃饭', completed: false }, { id: 2, title: '睡觉', completed: false }, { id: 3, title: '打豆豆', completed: true }] }, methods: { // 3.3.4 删除任务项 根据子组件传递过来的 id 删除对应的数据 removeTodo(delIndex) { this.todos.splice(delIndex, 1) }, // 保存编辑项 saveEdit(editText, item, index) { console.log(item, index, '-------------') // 1. 拿到文本框中的数据 // 非空校验 // 如果为空,则直接删除这个 item // 如果不为空,则修改任务项的 title 数据 // 程序员要具有工匠精神:优化简写 // !editText.length ? // this.todos.splice(index, 1) : // item.title = editText if (!editText.length) { // 将元素直接从数组中移除 return this.todos.splice(index, 1) } // 2. 将数据设置到任务项中 item.title = editText // 3. 去除 editing 样式 this.currentEditing = null }, // 删除所有已完成任务项 removeAllDone() { this.todos = this.todos.filter(item => !item.completed) }, # 3.4.3 把当前li的数据 赋值给 currentEditing 即让当前li 绑定 类名 aaaa(item) { this.currentEditing = item } }, computed: { }, components: { myheader, mylist, } })
script> body> html>
4 抽离fotter 部分
  • 4.1 把footer 部分的代码封装到一个组件中
  • 4.2 实现 未选中部分的展示
  • 4.3 删除已经选中的
 <section id="todoapp" class="todoapp">
    
        <myfotter :leftcount="leftCount" @delete-all-done="removeAllDone">myfotter>

    section>

<script>
		# 4.1 把footer 部分的代码封装到一个组件中 
        var myfotter = {
            props: ['leftcount'],
            template: `
            
{{leftcount}} item left
`
, methods: { deleteAll() { this.$emit("delete-all-done") } } } new Vue({ computed: { leftCount: function() { return this.todos.filter(item => !item.completed).length }, }, components: { myheader, mylist, myfotter } })
script>
todos接口案例
1 请求后台接口list 获取 数据展示到页面上
  • 发送ajax请求
  • 在mounted 钩子中将数据渲染到页面上
axios.defaults.baseURL = 'http://localhost:3001/';

new Vue({
     data: {
                currentEditing: null,
                todos: []
     },	
	  mounted() {
          		# 1.2 在mounted  钩子中将数据渲染到页面上
                this.getList()
            },
      methods: {
          		# 1.1 发送ajax请求
                getList() {
                    axios.get('list').then(res => {
                        console.log(res.data)
                        this.todos = res.data
                    })
                }
       }          

})
2 增加内容
  • 在回车事件中发送ajax请求
    • 我们已经封装好的 addTodo 方法中发送ajax请求
  • 将用户输入的内容添加到后台
    • 把用户输入的内容传递给后台
  • 因为我们所有的数据增删改查都是在父组件中修改 所有ajax也在父组件的 方法中发送
addTodo(todoText) {
                    axios.post('add', {
                            title: todoText,
                        }).then(res => {
                        	#  在请求成功之后重新渲染页面
                            this.getList()
                        })
                    // 清空文本框
                    event.target.value = ''
 },                  event.target.value = '' },
3 双击修改列表信息
  • 按回车键或者失去焦点的时候获取到用户信息
    • 这里需要把当前列表信息的id获取到
  • 把收集到的用户信息发送到后台
##  子组件中   需要把当前id 传递过去
   
         
 saveEdit(item, event) {
                    var editText = event.target.value.trim()
                    console.log(item, '--------')
                    this.$emit("save-edit", editText, item)
 },

### 父组件方法
### 因为我们所有的数据增删改查都是在父组件中修改 所有ajax也在父组件的 方法中发送
// 保存编辑项
         saveEdit(editText, item) {
				axios.put(`list/${item.id}`, {
						title: editText,
                    }).then(res => {
                        this.getList()
                         // 3. 去除 editing 样式
                          this.currentEditing = null
                    })

                   
                }

4 删除列表信息

  • 点击按钮 删除当前列表信息
    • 需要把当前列表的id传递过去
  • 发送ajax请求 根据id 删除当前信息
# 4.1  需要把删除按钮的id 传递过去 


# 父组件
### 因为我们所有的数据增删改查都是在父组件中修改 所有ajax也在父组件的 方法中发送

  // 删除任务项
  removeTodo(delIndex) {
      axios.delete(`list/${delIndex}`).then(res => {
          this.getList()
      })
  },

5 删除全部完成
  • 在fotter 的Clear completed 的事件处理函数中发送ajax 请求删除所有complete 为true 的
# 父组件
### 因为我们所有的数据增删改查都是在父组件中修改 所有ajax也在父组件的 方法中发送
   removeAllDone() {
       axios.delete('deleteall').then(res=>
           this.getList()
       })
6 实现全选功能
  • 在toggleStat1 中发送ajax请求 根据当前复选框选中状态 修改后台数据中对应的 complete 值
#2  把数据更新放在父组件中 
 

computed: {
                toggleStat1: {
                    get() {
                        return this.todos.every(item => item.completed)
                    },
                    set(val) {
                        axios.get(`all/${Number(val)}`).then(res => {
                            #1 子组件通知父组件更新数据
                            this.$emit('get-list')
                        })

                    }
                }
  }              

你可能感兴趣的:(Vue,Angular,React)