jirengu-inc / jrg-project-5

一个在线简历编辑器教程。
102 stars 13 forks source link

Get the shit done! #3

Open FrankFang opened 7 years ago

FrankFang commented 7 years ago

首先新建项目目录

cp -r step-2 step-3

这样我们就可以基于之前的代码做新任务,同时不改动之前的代码。

学会一个框架的最好办法

学会一个框架的最好办法那就是——做毁一个项目。

接下来我们就要用 Vue.js 做一个待办事项小应用。简单起见,我们就不写 CSS 了,只用 HTML 和 JS 搞定。

我们的目标只有一个,就是搞清楚怎样用 Vue.js 进行开发。

需求

这个项目的英文名就暂定为 Todo,它有以下功能:

  1. 用户可以新建一个待办事项
  2. 用户可以删除一个待办事项
  3. 用户可以将一个待办事项标记为已完成
  4. 用户刷新页面之后,待办事项还在

Getting Started

由于我们现在对 Vue.js 还一无所知,所以就走一步算一步先。

首先我们用 HTML 描绘一下我们的界面

page.html

<html>
  <head>
    <meta charset=utf-8>
  </head>
  <body>
    <div id="app">
      <div class="newTask">
        <input type="text">
      </div>
      <ol class="todos">
      </ol>
    </div>
    <script src="bundle.js"></script>
  </body>
</html>
  1. charset 要加上,不然出现中文就乱码了
  2. 加一个 div#app,用于给 Vue 初始化
  3. div.newTask > input 用于让用户输入待办的内容
  4. ol.todos 用于容纳所有待办,每个待办就是一个 <li>

添加待办

接下来我们做第一个需求,添加待办。

做之前你要想好流程:

  1. 用户输入待办内容
  2. 用户按下回车
  3. 新的待办出现在 ol.todos

好的,开始做了。

import Vue from 'vue'

var app = new Vue({
  el: '#app',
  data: {
    newTodo: '',
    todoList: []
  }
})                                                               

我们用 todoList 数组作为所有待办事项的容器,newTask 作为 input 的值。

为什么要有 data?

这里出现了第一个令我们费解的地方——「为什么我们需要将 DOM 与 JS 变量(data)对应起来」。

如果我们用 jQuery 来写,直接在 input 的键盘事件中取出 input.value,构造一个 <li>,插入到 ol.todos 就完了嘛。对不对?

这就是框架和库的区别了。jQuery 作为一个库,你想怎么用就怎么用,但是你在使用一个框架的时候,有很多「指导思想」是你要遵循的。Vue 的指导思想之一就是「尽量不要操作 DOM」,因为这个框架会帮你操作 DOM。

绑定数据

      <div class="newTask">
        <input type="text" v-model="newTodo">
      </div>

这一句将 input.value 与 data.newTodo 绑定起来了,而且是双向的:

  1. 只要 input.value 被用户改了,data.newTodo 就会变成一样的值;
  2. 只要 data.newTodo 被 JS 改了,input.value 就会变成一样的值。

怎么验证呢?

首先我们来验证在 JS 里改变 newTodo,input.value 就会变:

import Vue from 'vue'

var app = new Vue({
  el: '#app',
  data: {
    newTodo: '',
    todoList: []
  },
  created: function(){
    let i = 0
    setInterval(()=>{
      this.newTodo = i // this.newTodo 就是 data.newTodo,实际上 this.newTodo 是 data.newTodo 的代理
      i+= 1
    },1000)
  }
})                                                               

运行 webpack,打开 page.html,可以看到 input 的值自己变化着。

Tips:如果你不想每次都运行 webpack,那么你可以新开一个命令行窗口,运行 webpack --watch,那么 webpack 就会在每次 JS 文件变化时自动重新运行。

接下来验证 input.value 改变会导致 data.newTodo 变化:

import Vue from 'vue'

var app = new Vue({
  el: '#app',
  data: {
    newTodo: '',
    todoList: []
  },
  created: function(){
    setInterval(()=>{
      console.log(this.newTodo)
    },1000)
  }
})

F12 打开 console,然后在 input 里输入一些字符试试。

以上,就是双向绑定。

细节请自行查看 https://cn.vuejs.org/v2/guide/forms.html

绑定事件

我们需要在用户敲击 回车 的时候,在 data.todoList 里新建一个对象。

如何监听用户的键盘事件呢?请查看 https://cn.vuejs.org/v2/guide/events.html

看完这一节,你就能写出以下代码了:

app.js

import Vue from 'vue'

var app = new Vue({
  el: '#app',
  data: {
    newTodo: '',
    todoList: []
  },
  methods: {
    addTodo: function(){
      this.todoList.push({
        title: this.newTodo,
        createdAt: new Date()
      })
      console.log(this.todoList)
    }
  }
})   

page.html

      <div class="newTask">
        <input type="text" v-model="newTodo" @keypress.enter="addTodo">
      </div>

这时你刷新 page.html,在 input 里面输入 回车,就会在控制台看到 todoList 不是空字符串了:

展示新待办

虽然 data.todoList 已经含有一个新的项目了,但是页面里却没有展示。

根据 https://cn.vuejs.org/v2/guide/list.html 写出下面代码:

page.html

      <ol class="todos">
        <li v-for="todo in todoList">
          {{ todo.title }}
        </li>
      </ol>

然后重新刷新页面,在 input 输入一些字符,回车。你就会看到新增成功了:

优化

按照正常人的逻辑,添加成功后,input 的值应该清空,于是我们改写 app.js:

app.js

  methods: {
    addTodo: function(){
      this.todoList.push({
        title: this.newTodo,
        createdAt: new Date()
      })
      this.newTodo = ''  // 变成空
    }
  }

刷新试试效果如何吧。

标记为完成

思路:

  1. 给每一个 todo 添加一个 done 属性
  2. 给每一个 <li> 里面添加一个 checkbox
  3. 参考 https://cn.vuejs.org/v2/guide/forms.html#复选框 ,将 done 和 checkbox 双向绑定。

代码如下:

app.js

  methods: {
    addTodo: function(){
      this.todoList.push({
        title: this.newTodo,
        createdAt: new Date(),
        done: false // 添加一个 done 属性
      })
      this.newTodo = ''
    }
  }

page.html

      <ol class="todos">
        <li v-for="todo in todoList">
          <input type="checkbox" v-model="todo.done"> {{ todo.title }}

          <span v-if="todo.done">已完成</span>
          <span v-else>未完成</span>
        </li>
      </ol>

效果如下:

删除待办

思路:

  1. 在每一项后面添加一个删除按钮
  2. 点击按钮则从 data.todoList 中删除该项

代码如下:

app.js

  methods: {
    addTodo: function(){
      this.todoList.push({
        title: this.newTodo,
        createdAt: new Date(),
        done: false // 添加一个 done 属性
      })
      this.newTodo = ''
    },
    // 加了👇这个函数
    removeTodo: function(todo){
      let index = this.todoList.indexOf(todo) // Array.prototype.indexOf 是 ES 5 新加的 API
      this.todoList.splice(index,1) // 不懂 splice?赶紧看 MDN 文档!
    }
  }

page.html

      <ol class="todos">
        <li v-for="todo in todoList">
          <input type="checkbox" v-model="todo.done"> {{ todo.title }}

          <span v-if="todo.done">已完成</span>
          <span v-else>未完成</span>

          <button @click="removeTodo(todo)">X</button>  <!-- 👈 加了一个按钮 -->
        </li>
      </ol>

效果如下(GIF有点大,请稍等或开代理)

保存待办事项

我们发现每次刷新页面,待办就没了。

这是因为这些代码都保存在内存里,而内存是无法持久的。所以我们选择保存在 localStorage 中。

思路:

  1. 在用户关闭页面前,将数据保存在 localStorage 里
  2. 在用户进入页面后,立刻读取 localStorage

代码如下:

app.js

var app = new Vue({
  el: '#app',
  data: {
    newTodo: '',
    todoList: []
  },
  created: function(){
    // onbeforeunload文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/onbeforeunload
    window.onbeforeunload = ()=>{
      let dataString = JSON.stringify(this.todoList) // JSON 文档: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON
      window.localStorage.setItem('myTodos', dataString) // 看文档https://developer.mozilla.org/zh-CN/docs/Web/API/Window/localStorage
    }

    let oldDataString = window.localStorage.getItem('myTodos')
    let oldData = JSON.parse(oldDataString)
    this.todoList = oldData || []

  },
  methods: { ...

由于我们只涉及数据的变化,所以 page.html 不变。

让我看到你的应用

你可以将这个应用部署到 GitHub Pages 上。

  1. 新建一个 GitHub repo,或者使用你现有的 GitHub repo。
  2. 在 repo 的 Settings 页面里将 GitHub Pages 功能打开,并选中 master 分支,点 Save,你就会得到一个「部署地址」,比如我的地址是 https://jirengu-inc.github.io/jrg-project-5/
  3. 在这个部署地址后面接上你 repo 里的文件路径,也可以预览 HTML 了。比如我的预览页面是:https://jirengu-inc.github.io/jrg-project-5/step-3/page.html
  4. 由于国内访问 GitHub 较慢,所以你预览的时候可能看到 {{ }} 标记,不要紧,等一会就好。如果你不想让用户看见这些,可以看 https://cn.vuejs.org/v2/api/#v-cloak

致饥人谷学员

Just get this shit done.

把你的预览页面发到下面,你就成功了。

如果还有时间,建议看看 TodoMVC 项目。比我们这个应用复杂一丢丢,你已经可以独自完成 TodoMVC 了,如果你完成了,把你的链接放在下面单独 at 我。

挑战

  1. 你能否把 newTodo 的内容也保存下来,下次用户进入页面时,会显示之前输入但是还未提交的 newTodo 内容?
  2. 你能否把这个页面美化一下?
  3. 你能否添加「友好的」时间展示,让用户知道这个 todo 是什么时候创建的。
JeromeYangtao commented 7 years ago

预览 代码

superDCF commented 7 years ago

预览 代码

MasterGaoJin commented 7 years ago

preview code

n313893254 commented 7 years ago

预览 代码

success-cg commented 7 years ago

陈功-task3 todolist 预览 demo

FrankFang commented 7 years ago

sorry 没时间看了

13hoop commented 7 years ago

预览 代码

boloog commented 7 years ago

vue-todo boloog

kumabearplus commented 7 years ago

预览 代码

komolei commented 7 years ago

vue-todo 空末

selectyang commented 7 years ago

效果预览 代码

lc123123 commented 7 years ago

效果 代码

chengfengfengwang commented 7 years ago

预览 代码

jettzhang95 commented 7 years ago

Preview Code 后续还会进行改进

jamesXiao-coder commented 7 years ago

预览 代码

jamesXiao-coder commented 7 years ago

预览 代码

robbchan commented 7 years ago

预览 代码

zhaipanyu commented 7 years ago

预览

imgwho commented 7 years ago

预览地址 仓库地址 1705 郭文华

forsuccess commented 7 years ago

预览 代码

tcitds1 commented 7 years ago

预览

HuangHongRui commented 7 years ago

| Show | | Code |

andreaxiang commented 7 years ago

预览vue-todolist 已优化css 已保存newTodo内容,但是没有添加显示创建日期功能。 @FrankFang

huoguozhang commented 7 years ago

github地址

zhuyutrisla commented 7 years ago

预览

clementlxd commented 7 years ago

预览 https://clementlxd.github.io/vue-task2/page.html 代码 https://github.com/clementlxd/vue-task2

Zainking commented 7 years ago

https://github.com/Zainking/resumer/tree/practice/task3

Alfred-ZF commented 6 years ago

预览 代码

nciilin commented 6 years ago

代码 预览

wobenng commented 6 years ago

任务15班董杭彬 代码 预览

o0Chivas0o commented 6 years ago

任务15班 李智颖 预览 代码

upupdayday commented 6 years ago

预览 代码