美文网首页
🎑 VUE小教程-建一个TODO list (上)

🎑 VUE小教程-建一个TODO list (上)

作者: 秋衣队长 | 来源:发表于2019-01-21 23:00 被阅读0次

    这是个啥

    使用做一个VUE 3的todo-list。一边看油管,一遍学vue。
    Ref: https://youtu.be/Wy9q22isx3U

    0. 准备工作

    JavaScript

    1. ES 6 Module
    2. forEach, map, filter
    3. Arrow Functions
    4. Fetch API & Promises

    安装

    1. node

    2. 国内建议使用淘宝镜像

      • 设置淘宝镜像

          npm config set registry [http://registry.npm.taobao.org/](http://registry.npm.taobao.org/)
        
      • 换成原来的

          npm config set registry https://registry.npmjs.org/
        
    3. vue-cli

       npm install -g @vue/cli
      

    I. 建立项目

    一种方法比较传统,使用cli命令来建立。

    我一个文科生,将使用傻瓜式的UI界面哈哈🤗🤗😎😎清新脱俗,美丽大方~~~

    vue ui
    

    然后会抛出一个网页的UI界面,就很方便的管理和建立project了~

    Details Presets

    接下来就是美好的等待~~~~~~~~~

    等个一会儿!!!就这么建好了!!!!

    在tasks > serve > run test,然后稍等一会~~~


    点击open app~~~~

    建好了~~

    所以建好的东西,里头各种文件发生了什么?

    送便当的故事

    HelloWorld.vue是一个模板,然后App.vue将HellowWorld放到index.html中。结构大概是这样👇

    送便当的故事

    最关键的就是两个,不知道比喻成送外卖合适不合适。

    • index.html是宅男家。
    • App.vue是店家。
    • main.js是外卖小哥。

    店家负责做便当,然后外卖小哥取好便当后,送到宅男家。接着,就是宅男选择要不要吃咯~

    所以就是,App.vue负责做便当(就是HelloWorld.vue),然后main.js把便当送给index.html使用。

    便当是啥

    便当,也就是component folder里头的vue文件,主要有三个东西,

    <template>...</template>
    <script>...</script>
    <style scoped>....</style>
    

    template顾名思义就是模板;script是需要渲染的部分,可以根据不同的需要,搭配不同内容。

    style基本上就是CSS,scoped的意思就是,这个style仅限于这个vue component,是一个encapsulated的概念。


    就这么建完了~~~~~~~~~~~~~~
    教程结束~~~~~~~~~~~~~~~~~
    谢谢大家~~~~~~~~~~~~~~~~~

    好吧...还没开始做Todo list呢...


    II. 使用v-bind来渲染todo list

    0. 开始之前

    在建立todo list之前,先把代码清理一下,方便学习。👇

    首先,在component folder下,新建一个Todos.vue:

    <template>
        <div>
            <h1>Todos</h1>
        </div>
    </template>
    
    <script>
        export default {
            name: "Todos"
        }
    </script>
    
    <style scoped>
    
    </style>
    

    其次,把App.vue清理一下,引入Todos这个组件:

    <template>
      <div id="app">
        <Todos/>
      </div>
    </template>
    
    <script>
      import Todos from './components/Todos'
    export default {
      name: 'app',
      components: {
        HelloWorld
        Todos
      },
      data(){ ... }
    }
    

    1. 什么是v-bind

    其实就是<div>的一个属性。

    • 用在class上
    <div v-bind:class="{ active: isActive }"></div>
    
    • 用在数组上
    <div v-bind:class="[activeClass, errorClass]"></div>
    

    2. 使用v-bind来渲染数组

    • 👇 假设我有一组todo list,像这样:
        todos: [
                  {
                    id: 1,
                    title: "Todo One",
                    completed: false
                  },
                  {
                    id: 2,
                    title: "Todo Two",
                    completed: true
                  },
                  {
                    id: 3,
                    title: "Todo Three",
                    completed: false
                  }
                ]
    

    本来我需要做的是,分别做三个元素。但是,现在只要一个component,然后用一个for循环,来渲染。

    • 👇 修改Todos.vue,像这样:
        <template>
            <div>
                <div v-bind:key="todo.id" v-for="todo in todos">
                    <h3>{{ todo.title }}</h3>
                </div>
            </div>
        </template>
        
        <script>
            export default {
                name: "Todos",
                props: ["todos"]
            }
        </script>
    

    name是这个component的名字~

    props的作用,是父组件通过props和子组件沟通,就是方便把data传入。

    🤞注意喔,需要加一个v-bind:key,其实是一个eslint的问题。它希望你写出来的div tag,是有id的。于是,可以用v-bind:key 把id绑定上去。

    那么问题来了,怎么把data传入呢?

    • 让App.vue来,他是餐馆老大,买食材、定食谱,都是他喔!👇
        <template>
          <div id="app">
            <Todos v-bind:todos="todos"/>
          </div>
        </template>
    
        <script>
          import Todos from './components/Todos'
        
          export default {
            name: 'app',
            components: {
              Todos
            },
            data(){
              return {
                todos: [
                  {
                    id: 1,
                    title: "Todo One",
                    completed: false
                  }
                ]
              }
            }
          }
        </script>
    

    看看这里老大说了啥。

    1. “老弟,我有一组数据,叫todos”
    2. “老弟,这组数据,按照Todos.vue那个样式来展示”

    建好了,长这样👇

    3. 使用v-bind来渲染class

    但是,有两个问题:

    1. 能不能把task的css写好看点。
    2. task 2是做完的,所以,希望它被划掉,eg: Todo Two

    这个时候,就可以使用v-bind来渲染。

    首先在component folder下新建一个TodoItem.vue,然后写好3个css,分别来渲染3个class。

    • todo-item,是第一个问题
    • is-completed,是第二个问题
    • del,先放着....
        <style scoped>
            .todo-item {
                background: #f4f4f4;
                padding: 10px;
                border-bottom: 1px #ccc dotted;
            }
            
            .is-completed {
                text-decoration: line-through;
            }
            
            .del {
                background: #ff0000;
                color: #fff;
                border: none;
                padding: 5px 9px;
                border-radius: 50%;
                cursor: pointer;
                float: right;
            }
        </style>
    

    Step.1

    把之前Todos.vue中,改成这样👇

        <template>
            <div>
                <h1>Todos</h1>
                <div v-bind:key="todo.id" v-for="todo in todos">
                    <TodoItem v-bind:todo="todo"/>
                </div>
            </div>
        </template>
    

    主要就是多了一行<TodoItem v-bind:todo="todo"/>,目的是,把原来在todos中,用for循环渲染的文字,传入一个新的组件,就是TodoItem.vue。

    Step.2

    接下来,修改TodoItem.vue,让每个task使用todo-item的css。

        <template>
            <div class="todo-item">
                <p>{{todo.title}}</p>
            </div>
        </template>
    
        <script>
            export default {
                name: "TodoItem",
                props:["todo"]
            }
        </script>
    

    Step.3

    加一个v-bind。如果todo.completed为true,则使用is-completed这个class。

    同样,继续修改TodoItem.vue👇

        <template>
            <div class="todo-item" v-bind:class="{'is-completed': todo.completed}">
                <p>{{todo.title}}</p>
            </div>
        </template>
    

    这样就弄好咯~~~~~✌✌✌✌✌


    III.使用v-on来监听事件

    前面做的都是静态的数据渲染,接下来要做的是,使用v-on来监听事件。

    1. 什么是v-on

    可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

    👆这段引用vue官网教程,也就说,v-on会出发js代码。

    2. 使用v-on:change触发方法

    首先,加一个check box进TodoItem👇

        <template>
            <div class="todo-item" v-bind:class="{'is-completed': todo.completed}">
                <input type="checkbox">
                {{ todo.title }}
            </div>
        </template>
    

    接着,使用v-on绑定到checkbox上,关联到一个新建的method,我把它起名叫markCompleted

    <input type="checkbox" v-on:change="markCompleted">
    

    最后,在TodoItem的script中定义markCompleted这个method。

    <script>
        export default {
            name: "TodoItem",
            props:["todo"],
            methods: {
                markCompleted(){
                    this.todo.completed = ! this.todo.completed
                }
            }
        }
    </script>
    

    于是,点一下checkbox,就可以画一条线咯~像这样👇

    3. 使用v-on和$emit()

    $emit() 的作用:子组件通过$emit()和父组件沟通。

    官方文档写emit是这样的。

    这个是官方API的文档,而监听器就是v-on👇

    vm.$emit( eventName, […args] )

    • 参数

      • {string} eventName
      • [...args]

      触发当前实例上的事件。附加参数都会传给监听器回调。


    接下来开始写代码,实现,如何删除task。因为task是存在App.vue上的,所以要从从子组件一层一层往上通报,所以是这个顺序:TodoItem.vueTodo.vueApp.vue

    • TodoItem.vue

      这个时候,前面那个del的class就用上了。

            <template>
                <div class="todo-item" v-bind:class="{'is-completed': todo.completed}">
                    <p>
                        <input type="checkbox" v-on:change="markCompleted">
                        {{ todo.title }}
                        <button v-on:click="$emit('del-todo', todo.id)" class="del"></button>
                    </p>
                </div>
            </template>
    
    • Todo.vue

      继续往父组件传达

            <TodoItem v-bind:todo="todo" v-on:del-todo="$emit('del-todo', todo.id)"/>
    
    • App.vue

      这时候,在script中建一个deleteTodo的methods:在data中过滤掉子组件通报上来的id。

        <template>
          <div id="app">
            <Todos v-bind:todos="todos" v-on:del-todo="deleteTodo"/>
          </div>
        </template>
        
        <script>
          import Todos from './components/Todos'
        export default {
          name: 'app',
          components: {
            Todos
          },
          data(){ ... },
          methods: {
            deleteTodo(id){
              this.todos = this.todos.filter(todo => todo.id != id)
            }
          }
        }
    
    • 于是,我就可以删除掉task啦~~~画出来结构大概是这样👇

    🤞但是,因为这个是前端,没有实质变动数据库。所以,刷新一遍网页后,又会回去了。


    IIII. 加一些零件

    1. Header

    目前为止,界面上缺个header,所以利用vue,我来建个小header🤗🤗🤗👌👌👌

    首先,在component > layout> Header.vue

    Header.vue里头长这样:

        <template>
            <header class="header">
                <h1>Todo List</h1>
            </header>
        </template>
        
        <script>
            export default {
                name: "Header"
            }
        </script>
        
        <style scoped>
            .header {
                background: #333;
                color: #fff;
                text-align: center;
                padding: 10px;
            }
        
            .header a{
                color: #fff;
                padding-right: 5px;
            }
        </style>
    

    2. 加一个新增task的栏

    能够提交表单啦~

    同理,新增一个component > AddTodo.vue👇

        <template>
            <form>
                <input type="text" name="title" placeholder="Add new task ...">
                <input type="submit" value="Add" class="btn">
            </form>
        </template>
        
        <script>
            export default {
                name: "AddTodo"
            }
        </script>
        
        <style scoped>
            form {
                display: flex;
            }
        
            input[type="text"] {
                flex: 10;
                padding: 5px;
            }
        
            input[type="submit"]{
                flex: 2;
            }
        
            .btn {
                display: inline-block;
                border: none;
                background: #555;
                color: #fff;
                padding: 7px 20px;
                cursor: pointer;
            }
        
            .btn:hover {
                background: #666;
            }
        </style>
    

    然后再App.vue中增加这个header和新增按钮。

        <template>
          <div id="app">
            <Header />
            <AddTodo />
            <Todos v-bind:todos="todos" v-on:del-todo="deleteTodo"/>
          </div>
        </template>
    

    效果大概这样👆

    唔,增加了add功能,可是里头的功能还没写。
    今天先这样吧...明天继续完善。🤦‍♂️

    Ronn Liu 🙋‍♂️
    2019/01/21 📌

    相关文章

      网友评论

          本文标题:🎑 VUE小教程-建一个TODO list (上)

          本文链接:https://www.haomeiwen.com/subject/vrfkjqtx.html