2020-06-21

Getting started with Vue.js | Make an application from scratch

Before starting to write code, first go to the BootCDN to find the link to the latest version of the full version of Vue.js: https://cdn.bootcss.com/vue/2.6.10/vue.js , and the compressed version (vue. min.js), it (vue.js) contains a complete warning and debugging mode.

In order to keep it as simple as possible, this article does not use the Vue CLI to build the project, but instead introduces the Vue.js file directly into the HTML file as developed with jQuery.

If the code in the article does not understand something, my suggestion is: copy the code directly, see the effect, see the documentation, change the code, see the effect, and so on.

Declarative rendering

To understand the "Declarative Rendering" part of the basic part of Vue's official website , we can create the following code:



Preview the index.html file at this time and you will see the text Hello, Vue.js! on the page.

Component structure

We split the To-Do App to be divided into small components. At present, let's start with a component TodoList and a child component TodoItem. Through the familiar official website of the "basic components" tutorial we continue to do so.

TodoList component

Let's do the TodoList component first. I pasted the code over to facilitate access and study.
The code after this article is modified on the basis of the following code. At that time, I will only put the modified part of the code. When 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>
Things to note:

The component code needs to be placed before new Vue
When defining component data, data must be a function
The code in the template must be wrapped in an outer container (the outermost layer can only have one element)
Rewrite 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>Test1{{todos.filter(todo => todo.done === true).length}}</p>
        <p>Test1{{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">Done</div>
          <div class="button" v-show="todo.done">Show</div>
        </div>
      </div>
      `
    })

    new Vue({
      el: '#app',
      data: {
        todos: [
          {
            title: ' 1',
            content: '1',
            done: false
          },
          {
            title: ' 2',
            content: '2',
            done: true
          },
          {
            title: ' 3',
            content: '3',
            done: false
          },
          {
            title: ' 4',
            content: '4',
            done: false
          }
        ]
      }
    })
  </script>
</body>
</html>
Things to note:

The data is defined in the data of new Vue and needs to be passed to the TodoList component. Using the v-bind instruction, this code indicates that the todos variable is passed to the todos attribute of the TodoList component.
<div id="app">
  <todo-list v-bind:todos="todos"></todo-list>
</div>
The TodoList component defines props to receive the passed todos, which can be used directly in the component's template. Here we use v-for to render the data in a loop.
Vue.component('todo-list', {
  // ...  ...
  props: ['todos'],
    template:`
<div class="todo-list">
  <p>Test1{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Test1{{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">Done</div>
    <div class="button" v-show="todo.done">Done1</div>
  </div>
</div>
`
})
Although I have written classes for some elements but have not written any style yet, now open index.html preview like this:

image.png
TodoItem component
Now we extract the elements whose class is todo-item as separate components, and we do nothing but 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">Done</div>
  <div class="button" v-show="todo.done">Done1</div>
</div>
`
})

Vue.component('todo-list', {
  data: function() {
    return {}
  },
  props: ['todos'],
  template:`
<div class="todo-list">
  <p>Test1{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Test1{{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">Show ✏</div>
    <div class="button" v-show="!todo.done">Done</div>
    <div class="button" v-show="todo.done">Close</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">Close</button>
    </div>
  </div>
</div>
`,
  methods: {
    showForm: function() {
      this.isEditing = true
    },
    closeForm: function() {
      this.isEditing = false
    }
  }
})

The added code does the following:

Add an edit button in the TodoItem component, and add an isEditing attribute to distinguish whether it is in the editing state.
TodoItem component code when adding edit mode
Add and bind events that open and close edit mode

Remove Todo

Vue.component('todo-item', {
  // ...  ...
  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">Show ✏</div>
    <div class="button delete" v-on:click="deleteTodo(todo)">Delete ×××</div>
    <div class="button" v-show="!todo.done">Show</div>
    <div class="button" v-show="todo.done">Donw</div>
  </div>
  // ...  ...
</div>
`,
  methods: {
    // ...  ...
    deleteTodo(todo) {
      this.$emit('delete-todo', todo)
    }
  },
})
Add a delete button in the TodoItem component and add a delete method. This method sends 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>Test1:{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Test1:{{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">Show +++</div>
  <div class="form" v-show="isAdding">
    <div class="field">
    <label>Name</label>
    <input type="text" v-model="todo.title" />
    </div>
    <div class="field">
    <label>Name2</label>
    <input type="text" v-model="todo.content" />
    </div>
    <button class="close" v-on:click="saveForm">Save</button>
    <button class="close" v-on:click="closeForm">Close</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', {
  // ...  ...
  template:`
<div class="todo-list">
  <add-todo v-on:add-todo="addTodo"></add-todo>
  <p>Name{{todos.filter(todo => todo.done === true).length}}</p>
  <p>Length:{{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: {
    // ...  ...
    addTodo(todo) {
      this.todos.push(todo)
    }
  },
})
The AddTodo component only displays one add button by default. When the add button is clicked, the form to be filled out is displayed. After the filling is completed, click Save. An add-todo event and form information are sent to the parent component TodoList.

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

Complete Todo
In the TodoItem component, click the Finish button to send a complete-todo event to the parent component TodoList.

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

Vue.component('todo-item', {
 // ... ...
  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</div>
    <div class="button" v-show="todo.done">Save</div>
  </div>
  ......
`,
  methods: {
    // ... ...
    completeTodo(todo) {
      this.$emit('complete-todo', todo)
    }
  }
})

Vue.component('todo-list', {
  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: {
    completeTodo(todo) {
      const index = this.todos.indexOf(todo)
      this.todos[index].done = true
    }
  }
})

At this point, a To-Do App with basic functions is complete.

Complete code
The final complete code is as follows, you can directly take away and run a 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">Show +++</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">Save</button>
          <button class="close" v-on:click="closeForm">Close</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">Test</div>
            <div class="button delete" v-on:click="deleteTodo(todo)">Test ×××</div>
            <div class="button" v-show="!todo.done" v-on:click="completeTodo(todo)">Click</div>
            <div class="button" v-show="todo.done">Done</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">Test</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>Test:{{todos.filter(todo => todo.done === true).length}}</p>
        <p>Length:{{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: ' 1',
            content: '1',
            done: false
          },
          {
            title: ' 2',
            content: '2',
            done: true
          },
          {
            title: ' 3',
            content: '3',
            done: false
          },
          {
            title: ' 4',
            content: '4',
            done: false
          }
        ]
      }
    })
  </script>
</body>
</html>

1 comment:

  1. Getting started with Vue.js | Make an application from scratch

    Good post for new developers, students...

    They can learn many things about Vuejs...

    VueJS Development Company

    VueJS Development Services

    ReplyDelete