Vue TodoList

Todo App

# 安装Vue脚手架
$ npm i vue-cli -g
# 创建工程
$ vue init webpack-simple todos
$ cd todos
$ npm i
# 运行工程
$ npm run dev
# 浏览器访问
http://localhost:8080

目录结构

目录结构

启动入口

# /todos/src/main.js
//引入组件文件
import Vue from 'vue'
import App from './App.vue'
//创建vue对象实例
new Vue({
  el:'#app',
  //绘制vue的组件App以完成初始化
  //render()渲染机制采用Virtual DOM,一种比浏览器原生DOM更好性能的虚拟组件模型,具有更快的运行速度。
  render:h=>h(App)
});

首页结构

# todos/index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8"/>
</head>
<body>
  <div id="app"></app>
  <script src="/dist/build.js"></script>
</body>
</html>

组件系统

组件系统提供了一种抽象,使用独立可复用的小组件来构建大型应用,任意类型应用的界面都可以抽象为一个组件树。

组件树

单页组件

# /todos/src/App.vue
<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: 'app',
}
</script>
<style lang="scss">

</style>

Vue实例App所对应的页面元素

<div id="app"></div>
  • 一个Vue实例必须与一个页面元素绑定,Vue实例用作Vue的全局配置来使用。
    例如:向实例安装路由、资源插件、配置应用于全局的自定义过滤器、自定义指令等。
  • *.vue是Vue.js特有的文件格式,表示是一个Vue组件,被称为单页式组件。
  • *.vue文件可同时承载视图模板、样式定义、组件代码,使得组件的文件组织更为清晰与统一。

单页组件由三部分组成

  • <template> 视图模板
  • <script> 组件定义
  • <style> 组件样式表

插值

Vue视图模板是基于DOM实现的,意味着它是有效且可解析的HTML,Vue对一些特殊的特性做了增强。

# /todos/src/App.vue
<template>
  <div id="app">
    <h1>{{title}}</h1>
  </div>
</template>
<script>
export default {
  name: 'app',
  //data()返回Object对象,是一个对象的属性。使用函数返回是为了具有更高的灵活性。
  data () {
    return {
      //对象属性在视图中以插值语法即Mustache语法,Mustache标签会被相应数据对象的属性值替换,每当属性变化时它也会更新。
      title:'todos'
    }
  }
}
</script>
<style lang="scss">

</style>
  • 变量输出会采用插值的方式
  • 插值支持JS表达式运算和过滤器
  • {{}}引用的内容会被编码,若输出未被编码的文本可使用{{{}}}。

data有什么用呢?

将vue实例定义看成给一个类的定义,data相当于类内部字段属性的定义区域,在vue实例内其他地方可直接使用this引用data内定义的任何属性。

注意事项

  • Vue2组件模板必须有且仅有一个顶层元素,若组件模块内设置多个顶层元素间更会引起编译异常。
  • 组件中template属性是视图Viewtitle属性是模型Model

数据绑定

todos为了显示待办事项,这个数据模型应该是一个数组。

# /todos/src/App.vue
<template>
  <div id="app">
    <h1>{{title}}</h1>
    <ul>
      <li v-for="item,index in todos">
        <strong>{{index+1}}.</strong>
        <label>{{item.value}}</label></li>
    </ul>
  </div>
</template>
<script>
export default {
  name: 'app',
  data () {
    return {
      //标题
      title:'待办事项',
      //待办事项数组
      todos:[
        {value:'今天继续阅读Vue', active:false},
        {value:'项目注释补充', active:true},
        {value:'每日心得日志', active:false}
      ]
    }
  }
}
</script>
<style lang="scss">

</style>
待办事项

为什么没有操作DOM却将data内的变量设置到DOM上去了呢?

  • vue代码中直接操作DOM是不被推荐的
  • DOM是被vue直接托管的,绑定到DOM上的变量一旦变化,DOM对应的属性会被vue自动重绘而无需通过编码来显式地操作。

样式绑定

# 安装插件
& npm i less style-loader css-loader less-loader less -D

# webpack.config.js中设置modules
module: {
    rules: [
      {
        test:/\.less$/,
        loader:'style-loader!css-loader!less-loader'
      },
}

# 创建样式表
$ vim /todos/assets/style.less

# 组件中引入样式 App.vue
//使用import将样式表直接导入到代码
import './assets/style.less'
export default {
  //...
}

使用import将样式表直接导入到代码:

webpackless-loader会生成部分代码,在页面运行时将编译后的less代码生成到<style>标签内并自动插入到页面的<head>中。注意的是这种做法是全局的,样式会长期驻留页面直至vue的根(root)实例被销毁。

import './assets/style.less'

若希望样式表仅引用于当前组件,可使用<style scoped>,然后用CSS的@import导入样式表。

<style scoped>
@import './assets/app.less'
</style>

样式的绑定和属性的绑定方式是一样的

<li v-for="(item,index) in todos" v-bind:class="{'active':item.active}"></li>
# 简写
<li v-for="(item,index) in todos" :class="{'active':item.active}"></li>

完整代码

<template>
  <div id="app">
    <h1>{{title}}</h1>
    <ul>
      <li v-for="item,index in todos" :class="{'active':item.active}">
        <strong>{{index+1}}.</strong>
        <label>{{item.value}}</label></li>
    </ul>
  </div>
</template>
<script>
import './assets/style.less'
export default {
  name: 'app',
  data () {
    return {
      //标题
      title:'待办事项',
      //待办事项数组
      todos:[
        {value:'今天继续阅读Vue', active:false},
        {value:'项目注释补充', active:true},
        {value:'每日心得日志', active:false}
      ]
    }
  }
}
</script>
<style scoped>
@import './assets/app.less'
</style>

注意事项

vue的属性绑定语法是attribute="expression"attribute是元素接收的属性值,既可以是原生的也可以是自定义的,expression则是在vue组件内 由dataprops内定义的对象属性,或者是一个合法的表达式。若在元素属性中不加入:则认为是向这个属性赋上字符串值而非Vue组件上定义的属性引用。

样式绑定 VS 普通绑定

vue的样式绑定与普通属性绑定最大区别,凡是样式绑定必然是绑定到判断对象的,不能直接写CSS类名,即使要绑定一个固定的CSS类也都要写:class="{'classname':boolean}",除非不使用样式绑定。

样式类 VS 样式属性

无论绑定的是样式类还是样式属性,:class:style表达式内一定是一个JSON对象。

  • 样式类:class的JSON对象值是布尔型,true表示添加样式false表示移除样式。
  • 样式属性:style的JSON对象是样式配置项,key声明属性名,value是样式属性值。

过滤器

需求:为待办事项添加时间字段并格式化后显示

# 安装时间格式化专用包
$ npm i moment -S

$ vim /src/App.vue
<template>
  <div id="app">
    <h1>{{title}}</h1>
    <ul>
      <li v-for="(item,index) in todos" :class="{'active':item.active}">
        <strong>{{index+1}}.</strong>
        <label>{{item.value}}</label>
        <time>{{item.created_at | date}}</time>
      </li>
    </ul>
  </div>
</template>
<script>
import './assets/style.less'

//时间日期专用插件
import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-cn')

export default {
  name: 'app',
  data () {
    return {
      //标题
      title:'待办事项',
      //待办事项数组
      todos:[
        {value:'今天继续阅读Vue', active:false, created_at:Date.now()},
        {value:'项目注释补充', active:true, created_at:Date.now()+30000},
        {value:'每日心得日志', active:false, created_at:Date.now()-30000}
      ]
    }
  },
  //过滤器
  filters:{
    date(val){
      return moment(val).calendar()
    }
  }
}
</script>
<style scoped>
@import './assets/app.less'
</style>

注意:过滤器中是没有this引用的,过滤器内的this是一个undefined值。不要在过滤器中尝试引用组件实例的变量或方法,否则会引发空值引用的异常。

# package.json
{
  "name": "todos",
  "description": "A Vue.js project",
  "version": "1.0.0",
  "author": "junchow",
  "license": "MIT",
  "private": true,
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },
  "dependencies": {
    "moment": "^2.22.1",
    "normalize.less": "^1.0.0",
    "vue": "^2.5.11"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-3": "^6.24.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.11",
    "file-loader": "^1.1.4",
    "less": "^3.0.4",
    "less-loader": "^4.1.0",
    "node-sass": "^4.5.3",
    "sass-loader": "^6.0.6",
    "style-loader": "^0.21.0",
    "vue-loader": "^13.0.5",
    "vue-template-compiler": "^2.4.4",
    "webpack": "^3.6.0",
    "webpack-dev-server": "^2.9.1"
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容

  • 1.安装 可以简单地在页面引入Vue.js作为独立版本,Vue即被注册为全局变量,可以在页面使用了。 如果希望搭建...
    Awey阅读 11,032评论 4 129
  • vue概述 在官方文档中,有一句话对Vue的定位说的很明确:Vue.js 的核心是一个允许采用简洁的模板语法来声明...
    li4065阅读 7,227评论 0 25
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,050评论 0 29
  • 昨晚,在楼下就听到对面楼上两口子的争吵抱怨,还有孩子的哭声,起因是钱,一声不想过就滚吧! 不一会,看到一个女的抱着...
    榆钱花阅读 557评论 0 3
  • 甜蜜陷阱:陪伴是最长情的告白 或许,姑娘们会问:“该如何选择婚姻,婚姻是什么?” 的确,在当下社会,由于...
    我爱佩奇猪阅读 151评论 0 1