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

目录结构

4933701-0deeebc5d72edccc.png
目录结构

启动入口

# /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>

组件系统

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

4933701-71d49ba6c933ff10.png
组件树

单页组件

# /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>
4933701-19db5fff7e5d2cf9.png
待办事项

为什么没有操作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"
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值