Getting started with Vue.js: making a minimalist to do application from scratch

Writing time: December 10, 2019
Version information: Vue.js 2.6.10
Official documents: https://cn.vuejs.org/

Preface

One of the best ways to learn about Vue is "check out Vue.js's Official documents Take a look at the "basic" part. It's better to eat with this article.

Before you start writing code, first go BootCDN Find the link to the current full version of Vue.js on: https://cdn.bootcss.com/vue/2.6.10/vue.js , unlike the compressed version (vue.min.js), which contains the full warning and debugging mode.

To keep it as simple as possible, this article does not use Vue CLI To build the project, we introduce Vue.js directly into the HTML file as we did with jQuery development.

If the code in the article is not clear, my suggestion is: copy the code directly, see the effect, see the document, change the code, see the effect, and so on.

Declarative rendering

Get to know The declarative rendering part of the basic part of the Vue official website , we can create the following code:

Preview the index.html file, and you will see the text of Hello, Vue.js! On the page.

Component structure

We split the to do app into small components. At present, let's start with a component TodoList and a sub component TodoItem. Through familiarity "Component Basics" tutorial on the official website Let's move on.

TodoList component

Let's do the TodoList component first. I paste all the codes here for easy access and learning.
The code after this article is modified on the basis of the following code. Then I will only put the modified part of the code. If necessary, I will post all the code.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Vue.js To-Do App</title>
</head>
<body>
  <div id="app">
    <todo-list></todo-list>
  </div>

  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
  <script>
    Vue.component('todo-list', {
      data: function() {
        return {}
      },
      template:`
      <ul>
        <li>Todo A</li>
        <li>Todo B</li>
        <li>Todo C</li>
      </ul>
      `
    })

    new Vue({
      el: '#app',
      data: {}
    })
  </script>
</body>
</html>

Note:

  1. Component code needs to be put before new Vue
  2. When defining data for a component, data must be a function
  3. Code in template must have an outer container package (the outermost layer can only have one element)

Overwrite the TodoList component and add the required data:

<!DOCTYPE html>
<html lang="zh-hans">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Vue.js To-Do App</title>
</head>
<body>
  <div id="app">
    <todo-list v-bind:todos="todos"></todo-list>
  </div>

  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
  <script>
    Vue.component('todo-list', {
      data: function() {
        return {}
      },
      props: ['todos'],
      template:`
      <div class="todo-list">
        <p>Completed:{{todos.filter(todo => todo.done === true).length}}</p>
        <p>Hang in the air:{{todos.filter(todo => todo.done === false).length}}</p>
        <div class="todo-item" v-for="todo in todos">
          <div class="title">{{todo.title}}</div>
          <div class="content">{{todo.content}}</div>
          <div class="button" v-show="!todo.done">Click Finish</div>
          <div class="button" v-show="todo.done">Completed</div>
        </div>
      </div>
      `
    })

    new Vue({
      el: '#app',
      data: {
        todos: [
          {
            title: 'To do 1',
            content: 'Please copy your homework before class.',
            done: false
          },
          {
            title: 'To do 2',
            content: 'Go to the court to play basketball with friends between classes.',
            done: true
          },
          {
            title: 'To do 3',
            content: 'The English class is deliberately mischievous and let the beautiful English teacher notice and ask me questions.',
            done: false
          },
          {
            title: 'To do 4',
            content: 'Run quickly after school, never listen to some people's words:「You wait for me after school」. ',
            done: false
          }
        ]
      }
    })
  </script>
</body>
</html>

Note:

  1. The data is defined in the data of new Vue, which needs to be passed to the TodoList component, using the v-bind instruction. This code indicates that the todos variable is passed to the TodoList component's todos attribute.
<div id="app">
  <todo-list v-bind:todos="todos"></todo-list>
</div>
  1. The TodoList component defines props to receive the passed todos, which can be used directly in the template of the component. Here we use v-for to loop through the rendered data.
Vue.component('todo-list', {
  // ... omit
  props: ['todos'],
    template:`
<div class="todo-list">
  <p>Completed:{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Hang in the air:{{todos.filter(todo => todo.done === false).length}}</p>
  <div class="todo-item" v-for="todo in todos">
    <div class="title">{{todo.title}}</div>
    <div class="content">{{todo.content}}</div>
    <div class="button" v-show="!todo.done">Click Finish</div>
    <div class="button" v-show="todo.done">Completed</div>
  </div>
</div>
`
})

Although I wrote a class for some elements, I haven't written any style yet. Now I open the index.html preview as follows:


TodoItem component

Now we extract the elements whose class is todo item as a separate component. Besides, we do nothing. The preview effect is the same as before.

Vue.component('todo-item', {
  props: ['todo'],
  template: `
<div class="todo-item">
  <div class="title">{{todo.title}}</div>
  <div class="content">{{todo.content}}</div>
  <div class="button" v-show="!todo.done">Click Finish</div>
  <div class="button" v-show="todo.done">Completed</div>
</div>
`
})

Vue.component('todo-list', {
  data: function() {
    return {}
  },
  props: ['todos'],
  template:`
<div class="todo-list">
  <p>Completed:{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Hang in the air:{{todos.filter(todo => todo.done === false).length}}</p>
  <todo-item
    v-for="(todo, index) in todos" v-bind:key="index"
    v-bind:todo="todo">
  </todo-item>
</div>
`
})

Next, add the editing function

Vue.component('todo-item', {
  props: ['todo'],
  data: function() {
    return {
      isEditing: false
    }
  },
  template: `
<div>
  <div class="todo-item" v-show="!isEditing">
    <div class="title">{{todo.title}}</div>
    <div class="content">{{todo.content}}</div>
    <div class="button edit" v-on:click="showForm">edit ✏</div>
    <div class="button" v-show="!todo.done">Click Finish</div>
    <div class="button" v-show="todo.done">Completed</div>
  </div>
  <div class="todo-item" v-show="isEditing">
    <div class="form">
      <div class="field">
        <label>Title</label>
        <input type="text" v-model="todo.title" />
      </div>
      <div class="field">
        <label>Content</label>
        <input type="text" v-model="todo.content" />
      </div>
      <button class="close" v-on:click="closeForm">Save and close edit mode</button>
    </div>
  </div>
</div>
`,
  methods: {
    showForm: function() {
      this.isEditing = true
    },
    closeForm: function() {
      this.isEditing = false
    }
  }
})

The added code does the following:

  1. Add the Edit button in the TodoItem component, and add an isEditing property to distinguish whether it is an editing state.
  2. Code of TodoItem component when adding edit mode
  3. Add and bind events that turn edit mode on and off

Delete Todo

Vue.component('todo-item', {
  // ... omit
  template: `
<div>
  <div class="todo-item" v-show="!isEditing">
    <div class="title">{{todo.title}}</div>
    <div class="content">{{todo.content}}</div>
    <div class="button edit" v-on:click="showForm">edit ✏</div>
    <div class="button delete" v-on:click="deleteTodo(todo)">delete ×××</div>
    <div class="button" v-show="!todo.done">Click Finish</div>
    <div class="button" v-show="todo.done">Completed</div>
  </div>
  // ... omit
</div>
`,
  methods: {
    // ... omit
    deleteTodo(todo) {
      this.$emit('delete-todo', todo)
    }
  },
})

Add the delete button in the TodoItem component, and add the delete method, which will send a delete todo event and the todo data to be deleted to the parent component TodoList.

Add a delete event to the parent component TodoList and listen to the delete todo event from the child component.

Vue.component('todo-list', {
  data: function() {
    return {}
  },
  props: ['todos'],
  template:`
<div class="todo-list">
  <p>Completed:{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Hang in the air:{{todos.filter(todo => todo.done === false).length}}</p>
  <todo-item
  v-for="(todo, index) in todos" v-bind:key="index"
  v-bind:todo="todo" v-on:delete-todo="deleteTodo"
  >
  </todo-item>
</div>
`,
  methods: {
    deleteTodo(todo) {
      const index = this.todos.indexOf(todo)
      this.todos.splice(index, 1)
    }
  },
})

Add Todo

Create a new AddTodo component and add the component to the TodoList component.

Vue.component('add-todo', {
  data: function() {
    return {
      isAdding: false,
      todo: {
        title: '',
        content: '',
        done: false
      }
    }
  },
  template: `
<div>
  <div v-on:click="showForm">Add to +++</div>
  <div class="form" v-show="isAdding">
    <div class="field">
    <label>Title</label>
    <input type="text" v-model="todo.title" />
    </div>
    <div class="field">
    <label>content</label>
    <input type="text" v-model="todo.content" />
    </div>
    <button class="close" v-on:click="saveForm">Preservation</button>
    <button class="close" v-on:click="closeForm">cancel</button>
  </div>
</div>
`,
  methods: {
    showForm() {
      this.isAdding = true
    },
    saveForm() {
      if (this.todo.title && this.todo.content) {
        this.$emit('add-todo', this.todo)
        this.closeForm()
      }
    },
    closeForm() {
      this.isAdding = false
      this.todo = {
        title: '',
        content: '',
        done: false
      }
    }
  }
})

Vue.component('todo-list', {
  // ... omit
  template:`
<div class="todo-list">
  <add-todo v-on:add-todo="addTodo"></add-todo>
  <p>Completed:{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Hang in the air:{{todos.filter(todo => todo.done === false).length}}</p>
  <todo-item
    v-for="(todo, index) in todos" v-bind:key="index"
    v-bind:todo="todo" v-on:delete-todo="deleteTodo"
  >
  </todo-item>
</div>
`,
  methods: {
    // ... omit
    addTodo(todo) {
      this.todos.push(todo)
    }
  },
})

By default, the add todo component only displays one add button. When clicking the Add button, the form to be filled in will be displayed. After filling in, click Save to send an add todo event and form information to the parent component TodoList.

The parent component TodoList listens for the add todo event and adds a piece of data sent by the AddTodo component to the todos data after the event is triggered.

Finish Todo

In the TodoItem component, click the finish button to send the complete todo event to the parent component TodoList.

The parent component TodoList listens for the complete todo event and marks the completed data from the todos data after the event is triggered.

Vue.component('todo-item', {
 // ... omit
  template: `
<div>
  <div class="todo-item" v-show="!isEditing">
    <div class="title">{{todo.title}}</div>
    <div class="content">{{todo.content}}</div>
    <div class="button edit" v-on:click="showForm">edit ✏</div>
    <div class="button delete" v-on:click="deleteTodo(todo)">delete ×××</div>
    <div class="button" v-show="!todo.done" v-on:click="completeTodo(todo)">Click Finish</div>
    <div class="button" v-show="todo.done">Completed</div>
  </div>
  ......
`,
  methods: {
    // ... omit
    completeTodo(todo) {
      this.$emit('complete-todo', todo)
    }
  }
})

Vue.component('todo-list', {
  // ... omit
  template:`
<div class="todo-list">
  ......
  <todo-item
    v-for="(todo, index) in todos" v-bind:key="index"
    v-bind:todo="todo"
    v-on:delete-todo="deleteTodo"
    v-on:complete-todo="completeTodo"
  >
  </todo-item>
</div>
`,
  methods: {
    // ... omit
    completeTodo(todo) {
      const index = this.todos.indexOf(todo)
      this.todos[index].done = true
    }
  }
})

So far, a fully functional to do app has been completed.

Complete code

The final complete code is as follows. You can take it away and run it for preview.

<!DOCTYPE html>
<html lang="zh-hans">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Vue.js To-Do App</title>
</head>
<body>
  <div id="app">
    <todo-list v-bind:todos="todos"></todo-list>
  </div>

  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
  <script>
    Vue.component('add-todo', {
      data: function() {
        return {
          isAdding: false,
          todo: {
            title: '',
            content: '',
            done: false
          }
        }
      },
      template: `
      <div>
        <div v-on:click="showForm">Add to +++</div>
        <div class="form" v-show="isAdding">
          <div class="field">
            <label>Title</label>
            <input type="text" v-model="todo.title" />
          </div>
          <div class="field">
            <label>content</label>
            <input type="text" v-model="todo.content" />
          </div>
          <button class="close" v-on:click="saveForm">Preservation</button>
          <button class="close" v-on:click="closeForm">cancel</button>
        </div>
      </div>
      `,
      methods: {
        showForm() {
          this.isAdding = true
        },
        saveForm() {
          if (this.todo.title && this.todo.content) {
            this.$emit('add-todo', this.todo)
            this.closeForm()
          }
        },
        closeForm() {
          this.isAdding = false
          this.todo = {
            title: '',
            content: '',
            done: false
          }
        }
      },
    })

    Vue.component('todo-item', {
      props: ['todo'],
      data: function() {
        return {
          isEditing: false
        }
      },
      template: `
      <div>
          <div class="todo-item" v-show="!isEditing">
            <div class="title">{{todo.title}}</div>
            <div class="content">{{todo.content}}</div>
            <div class="button edit" v-on:click="showForm">edit ✏</div>
            <div class="button delete" v-on:click="deleteTodo(todo)">delete ×××</div>
            <div class="button" v-show="!todo.done" v-on:click="completeTodo(todo)">Click Finish</div>
            <div class="button" v-show="todo.done">Completed</div>
          </div>
          <div class="todo-item" v-show="isEditing">
            <div class="form">
              <div class="field">
                <label>Title</label>
                <input type="text" v-model="todo.title" />
              </div>
              <div class="field">
                <label>Content</label>
                <input type="text" v-model="todo.content" />
              </div>
              <button class="close" v-on:click="closeForm">Save and close edit mode</button>
            </div>
          </div>
      </div>
      `,
      methods: {
        showForm: function() {
          this.isEditing = true
        },
        closeForm: function() {
          this.isEditing = false
        },
        deleteTodo(todo) {
          this.$emit('delete-todo', todo)
        },
        completeTodo(todo) {
          this.$emit('complete-todo', todo)
        }
      },
    })

    Vue.component('todo-list', {
      data: function() {
        return {}
      },
      props: ['todos'],
      template:`
      <div class="todo-list">
        <add-todo v-on:add-todo="addTodo"></add-todo>
        <p>Completed:{{todos.filter(todo => todo.done === true).length}}</p>
        <p>Hang in the air:{{todos.filter(todo => todo.done === false).length}}</p>
        <todo-item
          v-for="(todo, index) in todos" v-bind:key="index"
          v-bind:todo="todo"
          v-on:delete-todo="deleteTodo"
          v-on:complete-todo="completeTodo"
        >
        </todo-item>
      </div>
      `,
      methods: {
        deleteTodo(todo) {
          const index = this.todos.indexOf(todo)
          this.todos.splice(index, 1)
        },
        addTodo(todo) {
          this.todos.push(todo)
        },
        completeTodo(todo) {
          const index = this.todos.indexOf(todo)
          this.todos[index].done = true
        }
      },
    })

    new Vue({
      el: '#app',
      data: {
        todos: [
          {
            title: 'To do 1',
            content: 'Before class, you should copy your classmates' homework.',
            done: false
          },
          {
            title: 'To do 2',
            content: 'Go to the court to play basketball with friends between classes.',
            done: true
          },
          {
            title: 'To do 3',
            content: 'The English class is deliberately mischievous and let the beautiful English teacher notice and ask me questions.',
            done: false
          },
          {
            title: 'To do 4',
            content: 'Run quickly after school, never listen to some people's words:「You wait for me after school」. ',
            done: false
          }
        ]
      }
    })
  </script>
</body>
</html>

(end)

Keywords: Javascript Vue IE JQuery Attribute

Added by pandu345 on Wed, 25 Dec 2019 11:49:21 +0200