乐趣区

关于vue.js:编程鹿学Vuejs这一篇就够了万字学会通俗易懂

vue 概述

mvvm 模式

image-20201001110548401

  • M:即 Model,模型,包含数据和一些基本操作
  • V:即 View,视图,页面渲染后果
  • VM:即 View-Model,模型与视图间的双向操作(无需开发人员干预)

在 MVVM 之前,开发人员从后端获取须要的数据模型,而后要通过 DOM 操作 Model 渲染到 View 中。而后当用户操作视图,咱们还须要通过 DOM 获取 View 中的数据,而后同步到 Model 中。

而 MVVM 中的 VM 要做的事件就是把 DOM 操作齐全封装起来,开发人员不必再关怀 Model 和 View 之间是如何相互影响的:

  • 只有咱们 Model 产生了扭转,View 上天然就会体现进去。
  • 当用户批改了 View,Model 中的数据也会跟着扭转。

把开发人员从繁琐的 DOM 操作中解放出来,把关注点放在如何操作 Model 上。

mvvm 模式的劣势:

  1. 低耦合

视图(View)能够独立于 Model 变动和批改,一个 ViewModel 能够绑定到不同的 ”View” 上,当 View 变动时 Model 能够不变,当 Model 变动时 View 也能够不变

  1. 可重用性

能够把一些视图逻辑放在一个 ViewModel 外面,让多个 View 重用这段视图逻辑代码

  1. 独立开发

开发人员能够专一于业务逻辑和数据的开发(ViewModel),设计人员能够专一于页面设计。

而咱们明天要学习的,就是一款 MVVM 模式的框架:Vue

疾速入门

装置 vue

下载安装

下载地址:https://github.com/vuejs/vue

能够下载 2.5.16 版本 https://github.com/vuejs/vue/…

下载解压,失去 vue.js 文件。能够在页面中间接通过 script 引入 vue.js 文件

应用 cdn

或者也能够间接应用公共的 CDN 服务:

<!-- 开发环境版本,蕴含了用帮忙的命令行正告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

或者:

<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

Vue 入门案例(演示用,不做解说)

HTML 模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h2>{{name}},十分酷!</h2>
</div>
<script type="text/javascript"> var app = new Vue({
        el: "#app", // el 即 element,要渲染的页面元素
        data: {name: "Vue 测试"}
    });</script>
</body>
</html>
  • 首先通过 new Vue() 来创立 Vue 实例
  • 而后构造函数接管一个对象,对象中有一些属性:

    • el:是 element 的缩写,通过id 选中要渲染的页面元素,本例中是一个 div
    • data:数据,数据是一个对象,外面有很多属性,都能够渲染到视图中

      • name:这里指定了一个 name 属性
  • 页面中的 h2 元素中,通过{{name}} 的形式,来渲染刚刚定义的 name 属性

更神奇的在于,当你批改 name 属性时,页面会跟着变动。

双向绑定

对方才的案例进行简略批改:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <input type="text" v-model="num">
    <h2>
      {{name}},十分酷!有 {{num}} 个酷炫性能!</h2>
</div>
<script type="text/javascript"> var app = new Vue({
        el: "#app", // el 即 element,要渲染的页面元素
        data: {
            name: "Vue 测试",
            num: 1
        }
    });</script>
</body>
</html>
  • data 中增加了新的属性:num
  • 在页面中有一个 input 元素,通过 v-modelnum 进行绑定
  • 同时通过 {{num}} 在页面输入

能够察看到,输入框的变动引起了 data 中的 num 的变动,同时页面输入也跟着变动。

  • inputnum 绑定,inputvalue 值变动,影响到了 data 中的 num
  • 页面 {{num}} 与数据 num 绑定,因而 num 值变动,引起了页面成果变动。

没有任何 dom 操作,这就是双向绑定的魅力。

事件处理

在页面增加一个按钮:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <input type="text" v-model="num">
    <button v-on:click="num++"> 点我 </button>
    <h2>
      {{name}},十分酷!有 {{num}} 个酷炫性能!</h2>
</div>
<script type="text/javascript"> var app = new Vue({
        el: "#app", // el 即 element,要渲染的页面元素
        data: {
            name: "Vue 测试",
            num: 1
        }
    });</script>
</body>
</html>
  • 这里用 v-on 指令绑定点击事件,而不是一般的 onclick,而后间接操作num
  • 一般 onclick 是无奈间接操作 num

Vue 实例

创立 Vue 实例

每个 Vue 利用都是通过用 Vue 函数创立一个新的 Vue 实例开始的:

var vm = new Vue({// 选项})

在构造函数中传入一个对象,并且在对象中申明各种 Vue 须要的数据和办法,包含:

  • el
  • data
  • methods
  • … …等

接下来,一一介绍。

模板或元素

每个 Vue 实例都须要关联一段 Html 模板,Vue会基于此模板进行视图渲染;能够通过 el 属性来指定。

例如一段 html 模板:

<div id="app">
</div>

而后创立 Vue 实例,关联这个div

var vm = new Vue({el:"#app"})

这样,Vue就能够基于 idappdiv 元素作为模板进行渲染了。在这个 div 范畴以外的局部是无奈应用 vue 个性的。

数据

当 Vue 实例被创立时,它会尝试获取在 data 中定义的所有属性,用于视图的渲染,并且监督 data 中的属性变动,当 data 产生扭转,所有相干的视图都将从新渲染,这就是“响应式“零碎。

html:

<div id="app">
 <input type="text" v-model="name"/>
</div>

js:

var vm = new Vue({
  el:"#app",
  data:{name:"ZHANGSAN"}
})
  • name的变动会影响到 input 的值
  • input中输出的值,也会导致 vm 中的 name 产生扭转

办法

Vue 实例中除了能够定义 data 属性,也能够定义方法,并且在 Vue 的作用范畴内应用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <button v-on:click="add"> 点我 </button>
</div>
<script type="text/javascript"> var app = new Vue({
        el: "#app",
        data: {},
        methods: {add: function () {console.log("点我了...233")
            }
        }
    });</script>
</body>
</html>

生命周期钩子函数

每个 Vue 实例在被创立时都要通过一系列的初始化过程:创立实例,装载模板,渲染模板等。Vue 为生命周期中的每个状态都设置了钩子函数(监听函数)。每当 Vue 实例处于不同的生命周期时,对应的函数就会被触发调用。

所有的生命周期钩子主动绑定 this 上下文到实例中,因而你能够拜访数据,对属性和办法进行运算。

20200710065238953

生命周期

每个 Vue 实例在被创立之前都要通过一系列的初始化过程

生命周期函数

含意

beforeCreate(vue 对象创立前)

组件实例刚被创立,组件属性计算之前,比方 data 属性等

created(创立后)

模板编译、挂载之前

mounted(载入后)

模板编译、挂载之后

beforeUpdate(更新前)

组件更新之前

updated(更新后)

组件更新之后

beforeDestroy(销毁前)

组件销毁前调用

destroyed(销毁后)

组件销毁后调用

vm.$el:Vue 实例应用的根 DOM 元素

vm.$root:以后的 Vue 实例。

Vue 在实例化的过程中,会调用这些生命周期的钩子,给咱们提供了执行自定义逻辑的机会。那么,在这些 vue 钩子中,vue 实例到底执行了那些操作,咱们先看上面执行的例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 生命周期 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    {{message}}
</div>
<script type="text/javascript"> var vm = new Vue({
        el: "#app",
        data: {message: 'hello world'},
        beforeCreate: function () {console.log(this);
            showData('创立 vue 实例前', this);
        },
        created: function () {showData('创立 vue 实例后', this);
        },
        beforeMount: function () {showData('挂载到 dom 前', this);
        },
        mounted: function () {showData('挂载到 dom 后', this);
        },
        beforeUpdate: function () {showData('数据变动更新前', this);
        },
        updated: function () {showData('数据变动更新后', this);
        },
        beforeDestroy: function () {showData('vue 实例销毁前', this);
        },
        destroyed: function () {showData('vue 实例销毁后', this);
        }
    });
    function showData(process, obj) {console.log(process);
        console.log('data 数据:' + obj.message)
        console.log('挂载的对象:')
        console.log(obj.$el)
    }</script>
</body>
</html>

钩子函数

例如:created代表在 vue 实例创立后;

能够在 Vue 中定义一个 created 函数,代表这个期间的构造函数:

创立示例 html 页面如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    {{msg}}
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            // 初始化为空
            msg: ""
        },
        // 钩子函数
        created() {
            // this 示意 Vue 实例
            this.msg = "hello vue.created";
            console.log(this)
        }
    });</script>
</body>
</html>

this

能够看下在 vue 外部的 this 变量是谁,在 created 的时候,打印this

var app = new Vue({
        el:"#app",
        data:{msg: ""},
        // 钩子函数
        created() {
            //this 示意 vue 实例
            this.msg = "hello vue. created.";
            console.log(this);
        }
    });

控制台的输入; 总结:this 就是以后的 Vue 实例,在 Vue 对象外部,必须应用 this 能力拜访到 Vue 中定义的 data 内属性、办法等。

利用场景

  1. 在 beforeCreate 生命周期函数运行时,能够增加 loading 动画
  2. 在 created 生命周期函数运行时,能够完结 loading 动画,还能够做一些初始化,实现函数自执行等操作
  3. 最常常应用的是 mounted 生命周期函数

能够发动后端数据申请,取回数据

能够接管页面之间传递的参数

能够子组件向父组件传递参数等

指令

什么是指令?

指令 (Directives) 是带有 v- 前缀的非凡属性。例如在入门案例中的v-model,代表双向绑定。

插值表达式

花括号

格局:

{{表达式}}

阐明:

  • 该表达式反对 JS 语法,能够调用 js 内置函数(必须有返回值
  • 表达式必须有返回后果。例如 1 + 1,没有后果的表达式不容许应用,如:var a = 1 + 1;
  • 能够间接获取 Vue 实例中定义的数据或函数

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    {{msg}}
</div>
<script type="text/javascript"> var app = new Vue({
        el: "#app",
        data: {msg: "hello vue."}
    });</script>
</body>
</html>

插值闪动

应用 {{}} 形式在网速较慢时会呈现问题。在数据未加载实现时,页面会显示出原始的 {{}},加载结束后才显示正确数据,称为插值闪动。解决办法是通过 v -text 和 v -html 替换

v-text 和 v-html

应用 v-textv-html指令来代替 {{}}

阐明:

  • v-text:将数据输入到元素外部,如果输入的数据有 HTML 代码,会作为一般文本输入
  • v-html:将数据输入到元素外部,如果输入的数据有 HTML 代码,会被渲染

示例,革新原页面内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!--{{msg}}-->
    v-text:<span v-text="msg"></span><br/>
    v-html:<span v-html="msg"></span><br/>
</div>
<script type="text/javascript"> var app = new Vue({
        el: "#app",
        data: {
//            msg: "hello vue."
            msg: "<h2>hello vue.</h2>"
        }
    });</script>
</body>
</html>

并且不会呈现插值闪动,当没有数据时,会显示空白。

v-model

方才的 v-textv-html能够看做是单向绑定,数据影响了视图渲染,然而反过来就不行。

接下来学习的 v-model 是双向绑定,视图(View)和模型(Model)之间会相互影响。

既然是双向绑定,肯定是在视图中能够批改数据,这样就限定了视图的元素类型。

目前 v-model 的可应用元素有:

  • input
  • select
  • textarea
  • checkbox
  • radio
  • components(Vue 中的自定义组件)

基本上除了最初一项,其它都是表单的输出项。

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <input type="checkbox" value="Java" v-model="language">Java<br/>
    <input type="checkbox" value="PHP" v-model="language">PHP<br/>
    <input type="checkbox" value="Swift" v-model="language">Swift<br/>
    <h2>
        你抉择了:{{language.join(",")}}
    </h2>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {language: []
        }
    });</script>
</body>
</html>
  • 多个 checkbox 对应一个 model 时,model的类型是一个数组,单个 checkbox 值是 boolean 类型
  • radio对应的值是 input 的 value 值
  • inputtextarea 默认对应的 model 是字符串
  • select 单选对应字符串,多选对应也是数组

v-on

根本用法

v-on指令用于给页面元素绑定事件。

语法:

v-on: 事件名 ="js 片段或函数名"

简写语法:

@事件名 ="js 片段或函数名"

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!-- 间接写 js 片段 -->
    <button @click="num++"> 减少 </button>
    <!-- 应用函数名,该函数必须要在 vue 实例中定义 -->
    <button @click="decrement"> 缩小 </button>
    <h2>
        num={{num}}
    </h2>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {num: 1},
        methods: {decrement() {this.num--;}
        }
    });</script>
</body>
</html>

事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是十分常见的需要。

只管咱们能够在办法中轻松实现这点,但更好的形式是:办法只有纯正的数据逻辑,而不是去解决 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点结尾的指令后缀来示意的。

  • .stop:阻止事件冒泡
  • .prevent:阻止默认事件产生
  • .capture:应用事件捕捉模式
  • .self:只有元素本身触发事件才执行。(冒泡或捕捉的都不执行)
  • .once:只执行一次

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!-- 间接写 js 片段 -->
    <button @click="num++"> 减少 </button>
    <!-- 应用函数名,该函数必须要在 vue 实例中定义 -->
    <button @click="decrement"> 缩小 </button>
    <h2>
        num={{num}}
    </h2>
    <hr>
    事件冒泡测试:<br/>
    <div style="background-color: lightblue;width: 100px;height: 100px" @click="print('div 被点击了 ')">
        <button @click.stop="print(' 点击了 button')"> 点我试试 </button>
    </div>
    <br> 阻止默认事件:<br>
    <a href="http://www.baidu.com" @click.prevent="print(' 点击了超链接 ')"> 百度 </a>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {num: 1},
        methods: {decrement() {this.num--;},
            print(str) {console.log(str);
            }
        }
    });</script>
</body>
</html>

v-for

遍历数据渲染页面是十分罕用的需要,Vue 中通过 v-for 指令来实现。

遍历数组

语法:

v-for="item in items"
  • items:要遍历的数组,须要在 vue 的 data 中定义好。
  • item:循环变量

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="user in users">
            {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            users: [{"name": "小明", "age": 13, "gender": "男"},
                {"name": "小红", "age": 13, "gender": "女"},
                {"name": "小绿", "age": 4, "gender": "男"}
            ]
        }
    });</script>
</body>
</html>

数组角标

在遍历的过程中,如果须要晓得数组角标,能够指定第二个参数:

语法:

v-for="(item,index) in items"
  • items:要迭代的数组
  • item:迭代失去的数组元素别名
  • index:迭代到的以后元素索引,从 0 开始。

示例:

<div id="app">
    <ul>
        <li v-for="(user,index) in users">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
</div>

遍历对象

v-for除了能够迭代数组,也能够迭代对象。语法根本相似

语法:

v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
  • 1 个参数时,失去的是对象的值
  • 2 个参数时,第一个是值,第二个是键
  • 3 个参数时,第三个是索引,从 0 开始 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="user in users">
            {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
    <hr>
    <ul>
        <li v-for="(user,index) in users">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
    <hr>
    <ul>
        <!-- 1 个参数时,失去的是对象的值 -->
        <li v-for="value in person">
            {{value}}
        </li>
    </ul>
    <hr>
    <ul>
        <!-- 2 个参数时,第一个是值,第二个是键 -->
        <li v-for="(value,key) in person">
            {{value}}--{{key}}
        </li>
    </ul>
    <hr>
    <ul>
        <!-- 3 个参数时,第三个是索引,从 0 开始 -->
        <li v-for="(value,key,index) in person">
            {{value}}--{{key}} -- {{index}}
        </li>
    </ul>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            users: [{"name": "小明", "age": 13, "gender": "男"},
                {"name": "小红", "age": 13, "gender": "女"},
                {"name": "小绿", "age": 4, "gender": "男"}
            ],
            person: {"name": "zhangsan", "age": 13, "gender": "男", "address": "中国"}
        }
    });</script>
</body>
</html>

key

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的程序被扭转,Vue 将不会挪动 DOM 元素来匹配数据项的程序,而是简略复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

如果应用 key 这个性能能够无效的进步渲染的效率;key 个别应用在遍历完后,又增、减汇合元素的时候更有意义。

然而要实现这个性能,你须要给 Vue 一些提醒,以便它能跟踪每个节点的身份,从而重用和从新排序现有元素,你须要为每项提供一个惟一 key 属性。现实的 key 值是每项都有的且惟一的 id。也就是 key 是该的惟一标识。

示例:

<ul>
 <li v-for="(item,index) in items" :key="index"></li>
</ul>
  • 这里应用了一个非凡语法::key="" 前面会讲到,它能够让你读取 vue 中的属性,并赋值给 key 属性
  • 这里绑定的 key 是数组的索引,应该是惟一的

v-if 和 v-show

根本应用

v-if,顾名思义,条件判断。当失去后果为 true 时,所在的元素才会被渲染。

语法:

v-if="布尔表达式"

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="show = !show"> 点我 </button>
    <h2 v-if="show">
        hello vuejs.
    </h2>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {show: true}
    });</script>
</body>
</html>

与 v-for 联合

v-ifv-for呈现在一起时,v-for优先级更高。也就是说,会先遍历,再判断条件。

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="show = !show"> 点我 </button>
    <h2 v-if="show">
        hello vuejs.
    </h2>
    <hr>
    <ul>
        <li v-for="(user,index) in users" v-if="user.gender==' 女 '":key="index"style="background-color: deeppink">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            show: true,
            users: [{"name": "北京大学", "age": 8, "gender": "男"},
                {"name": "清华大学", "age": 12, "gender": "女"},
                {"name": "复旦大学", "age": 4, "gender": "男"},
                {"name": "南开大学", "age": 2, "gender": "女"}
            ]
        }
    });</script>
</body>
</html>

v-else

能够应用 v-else 指令来示意 v-if 的“else 块”:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="show = !show"> 点我 </button>
    <h2 v-if="show">
        hello vuejs.
    </h2>
    <hr>
    <ul v-if="show">
        <li v-for="(user,index) in users" v-if="user.gender==' 女 '":key="index"style="background-color: deeppink">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
        <li v-else style="background-color: blue">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            show: true,
            users: [{"name": "北京大学", "age": 8, "gender": "男"},
                {"name": "清华大学", "age": 12, "gender": "女"},
                {"name": "复旦大学", "age": 4, "gender": "男"},
                {"name": "南开大学", "age": 2, "gender": "女"}
            ]
        }
    });</script>
</body>
</html>

v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的前面,否则它将不会被辨认。v-else-if,顾名思义,充当 v-if 的“else-if 块”,能够间断应用:

<div v-if="type ==='A'">
 A
</div>
<div v-else-if="type ==='B'">
 B
</div>
<div v-else-if="type ==='C'">
 C
</div>
<div v-else>
 Not A/B/C
</div>

相似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

v-show

另一个用于依据条件展现元素的选项是 v-show 指令。用法大抵一样:

<h1 v-show="ok">Hello!</h1>

不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简略地切换元素的 CSS 属性display

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="show = !show"> 点我 </button>
    <h2 v-if="show">
        hello vuejs.
    </h2>
    <hr>
    <ul v-if="show">
        <li v-for="(user,index) in users" v-if="user.gender==' 女 '":key="index"style="background-color: deeppink">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
        <li v-else style="background-color: blue">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
    <hr>
    <h2 v-show="show">
        你好,世界!</h2>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            show: true,
            users: [{"name": "北京大学", "age": 8, "gender": "男"},
                {"name": "清华大学", "age": 12, "gender": "女"},
                {"name": "复旦大学", "age": 4, "gender": "男"},
                {"name": "南开大学", "age": 2, "gender": "女"}
            ]
        }
    });</script>
</body>
</html>

v-bind

属性上应用 vue 数据

看这样一个案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
    <style type="text/css"> div {
            width: 100px;
            height: 100px;
            color: white;
        }
        .red {background-color: red;}
        .blue {background-color: blue;} </style>
</head>
<body>
<div id="app">
    <button @click="color='red'"> 红色 </button>
    <button @click="color='blue'"> 蓝色 </button>
    <div :class="">
        点击按钮扭转背景色彩
    </div>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {color: "red"}
    });</script>
</body>
</html>

解读:

  • 页面有两个按钮,点击时,会扭转 Vue 实例中的 color 值,这个值与后面定义的 CSS 款式统一。
  • 目前 div 的 class 为空,心愿实现点击按钮后,div 的 class 款式会在.red 和.blue 之间切换

该如何实现?

大家可能会这么想,既然 color 值会动态变化为不同的 class 名称,那么咱们间接把 color 注入到 class 属性就好了,于是就这样写:

<div class="{{color}}"></div>

这样写是谬误的!因为插值表达式不能用在标签的属性中。

此时,Vue 提供了一个新的指令来解决:v-bind,语法:

v-bind: 属性名 ="Vue 中的变量"

例如,在这里咱们能够写成:

<div v-bind:class="color"></div>

不过,v-bind太麻烦,因而能够省略,间接写成: 属性名 ='属性值',即:

<div :class="color"></div>

class 属性的非凡用法

下面尽管实现了色彩切换,然而语法却比拟啰嗦。

Vue 对 class 属性进行了非凡解决,能够接管数组或对象格局

对象语法:能够传给 :class 一个对象,以动静地切换 class:

<div :class="{red: true,blue:false}"></div>
  • 对象中,key 是曾经定义的 class 款式的名称,如本例中的:red 和 blue
  • 对象中,value 是一个布尔值,如果为 true,则这个款式会失效,如果为 false,则不失效。

之前的案例能够改写成这样:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
    <style type="text/css"> div {
            width: 100px;
            height: 100px;
            color: white;
        }
        .red {background-color: red;}
        .blue {background-color: blue;} </style>
</head>
<body>
<div id="app">
    <button @click="color='red'"> 红色 </button>
    <button @click="color='blue'"> 蓝色 </button>
    <!--v-bind 简写为 :-->
    <div :class="color">
        点击按钮扭转背景色彩
    </div>
    <hr>
    <br>
    <button @click="bool=!bool"> 点我扭转上面色块的色彩 </button>
    <div :class="{red:bool, blue:!bool}">
        点击按钮扭转背景色彩
    </div>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            color: "red",
            bool:true
        }
    });</script>
</body>
</html>

首先 class 绑定的是一个对象:{red:bool, blue: !bool}

red 和 blue 两个款式的值别离是 bool 和!bool,也就是说这两个款式的失效标记恰好相反,一个失效,另一个生效。

bool 默认为 true,也就是说默认 red 失效,blue 不失效

当初只须要一个按钮即可,点击时对 bool 取反,天然实现了款式的切换

计算属性

在插值表达式中应用 js 表达式是十分不便的,而且也常常被用到。

然而如果表达式的内容很长,就会显得不够优雅,而且前期保护起来也不不便,例如上面的场景,有一个日期的数据,然而是毫秒值:

data:{birthday:1429032123201 // 毫秒值}

在页面渲染,心愿失去 yyyy-MM-dd 的款式则须要如下解决:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h2>
    你的生日是:{{new Date(birthday).getFullYear()}}-{{new Date(birthday).getMonth()+1}}-{{new Date(birthday).getDay()}}
 </h2>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {birthday: 1429032123201}
    });</script>
</body>
</html>

尽管能失去后果,然而十分麻烦。

Vue 中提供了计算属性,来代替简单的表达式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h2>
    你的生日是:{{new Date(birthday).getFullYear()}}-{{new Date(birthday).getMonth()+1}}-{{new Date(birthday).getDay()}}
    </h2>
    <hr>
    <h2>
    computed 计算形式;你的生日为:{{birth}}
    </h2>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {birthday: 1429032123201},
        computed: {birth() {const date = new Date(this.birthday);
                return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDay();}
        }
    });</script>
</body>
</html>

计算属性实质就是办法,然而肯定要返回数据。而后页面渲染时,能够把这个办法当成一个变量来应用。

过滤器

阐明

​ 官网说法:Vue.js 容许你自定义过滤器,可被用于一些常见的 == 文本格式化 ==。过滤器能够用在两个中央:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始反对)。过滤器应该被增加在 JavaScript 表达式的尾部,由“管道”符号批示。

​ 艰深的来说:过滤器是对行将显示的数据做进一步的筛选解决,而后进行显示,值得注意的是过滤器并没有扭转原来的数据,只是在原数据的根底上产生新的数据。

​ 过滤器的品种:

  • 全局过滤器
  • 部分过滤器

过滤器的应用步骤

定义过滤器
  • 全局过滤器

    Vue.filter('过滤器名称', function (value[,param1,...] ) {// 逻辑代码})
    
  • 部分过滤器

    new Vue({       
      filters: {'过滤器名称': function (value[,param1,...] ) {// 逻辑代码} 
        }    
    })
    
利用过滤器
{{表达式 |  过滤器名字}}

过滤器不带参数

案例 1:日期格式化
<body>
    <div id="myDiv">
        {{birthday | dateFormat}}
    </div>
    <script src="../js/vue.js"></script>
    <script src="../js/moment.js"></script>  // 须要引入一个日期解决的一个工具类
    <script type="text/javascript"> // 定义过滤器
        Vue.filter("dateFormat",function(value){return moment(value).format("YYYY-MM-DD HH:mm:ss");
        });
        const app = new Vue({
            el: "#myDiv",
            data: {birthday: new Date()
            }
        }); </script>
</body>
案例 2:文本格式化
<body>
    <div id="myDiv">
        {{message | messageFormat}} <br/>
        {{message}}       // 值并没有扭转
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> Vue.filter("messageFormat",function(value){return value.replace("很棒","优良");
        });
        const app = new Vue({
            el: "#myDiv",
            data: {message: "HelloWorld, 是一个很棒的青年"}
        }); </script>
</body>

过滤器带参数

<body>
    <div id="myDiv">
        {{birthday | dateFormat}}     <br/>  // 不传递格式化规范就用残缺写法
        {{birthday | dateFormat("YYYY-MM-DD") }} // 传入了格式化规范就用传递的写法进行格式化
    </div>
    <script src="../js/vue.js"></script>
    <script src="../js/moment.js"></script>
    <script type="text/javascript"> Vue.filter("dateFormat",function(value,pattern = "YYYY-MM-DD HH:mm:ss"){return moment(value).format(pattern);
        });
        const app = new Vue({
            el: "#myDiv",
            data: {birthday: new Date()
            }
        }); </script>
</body>

watch

监控

watch能够让咱们监控一个值的变动。从而做出相应的反馈。

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <input v-model="message">
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {message: "hello vue"},
        watch: {message(newValue, oldValue) {console.log("新值:" + newValue + ";旧值:" + oldValue)
            }
        }
    });</script>
</body>
</html>

深度监控

如果监控的是一个对象,须要进行深度监控,能力监控到对象中属性的变动,例如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <input type="text" v-model="message">
    <hr>
    <br>
    <input type="text" v-model="person.name"><br>
    <input type="text" v-model="person.age">
    <button @click="person.age++">+</button>
    <h2>
        姓名为:{{person.name}};年龄为:{{person.age}}
    </h2>
</div>
<script type="text/javascript"> let app = new Vue({
        el: "#app",
        data: {
            message: "hello vue",
            person: {"name": "zhangsan", "age": 12}
        },
        watch: {message(newValue, oldValue) {console.log("新值:" + newValue + ";旧值:" + oldValue)
            },
            person: {
                // 开启深度监控,能够监控到对象属性值的变动
                deep: true,
                // 监控的解决方法
                handler(obj) {console.log("name =" + obj.name + ", age=" + obj.age);
                }
            }
        }
    });</script>
</body>
</html>

变动:

以前定义监控时,person 是一个函数,当初改成了对象,并且要指定两个属性:

  • deep: 代表深度监控,不仅监控 person 变动,也监控 person 中属性变动
  • handler:就是以前的监控处理函数

组件化

在大型利用开发的时候,页面能够划分成很多局部。往往不同的页面,也会有雷同的局部。例如可能会有雷同的头部导航。

然而如果每个页面都单独开发,这无疑减少了咱们开发的老本。所以咱们会把页面的不同局部拆分成独立的组件,而后在不同页面就能够共享这些组件,防止反复开发。

全局组件

咱们通过 Vue 的 component 办法来定义一个全局组件。

<div id="app">
    <!-- 应用定义好的全局组件 -->
    <counter></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> // 定义全局组件,两个参数:1,组件名称。2,组件参数
    Vue.component("counter",{template:'<button v-on:click="count++"> 你点了我 {{ count}} 次,我记住了.</button>',
        data(){
            return {count:0}
        }
    })
    var app = new Vue({el:"#app"})</script>
  • 组件其实也是一个 Vue 实例,因而它在定义时也会接管:data、methods、生命周期函数等
  • 不同的是组件不会与页面的元素绑定,否则就无奈复用了,因而没有 el 属性。
  • 然而组件渲染须要 html 模板,所以减少了 template 属性,值就是 HTML 模板
  • 全局组件定义结束,任何 vue 实例都能够间接在 HTML 中通过组件名称来应用组件了。
  • data 必须是一个函数,不再是一个对象。

组件的复用

定义好的组件,能够任意复用屡次:

<div id="app">
    <!-- 应用定义好的全局组件 -->
    <counter></counter>
    <counter></counter>
    <counter></counter>
</div>

你会发现每个组件互不烦扰,都有本人的 count 值。怎么实现的?

组件的 data 属性必须是函数

当咱们定义这个 counter 组件时,它的 data 并不是像这样间接提供一个对象:

data: {count: 0}

取而代之的是,一个组件的 data 选项必须是一个函数,因而每个实例能够保护一份被返回对象的独立的拷贝:

data: function () {
  return {count: 0}
}

如果 Vue 没有这条规定,点击一个按钮就会影响到其它所有实例!

部分注册

一旦全局注册,就意味着即使当前你不再应用这个组件,它仍然会随着 Vue 的加载而加载。

因而,对于一些并不频繁应用的组件,咱们会采纳部分注册。

咱们先在内部定义一个对象,构造与创立组件时传递的第二个参数统一:

const counter = {template:'<button v-on:click="count++"> 你点了我 {{ count}} 次,我记住了.</button>',
    data(){
        return {count:0}
    }
};

而后在 Vue 中应用它:

var app = new Vue({
    el:"#app",
    components:{counter:counter // 将定义的对象注册为组件}
})
  • components 就是以后 vue 对象子组件汇合。

    • 其 key 就是子组件名称
    • 其值就是组件对象的属性
  • 成果与方才的全局注册是相似的,不同的是,这个 counter 组件只能在以后的 Vue 实例中应用

组件通信

通常一个单页利用会以一棵嵌套的组件树的模式来组织:

image-20201001195026231

  • 页面首先分成了顶部导航、左侧内容区、右侧边栏三局部
  • 左侧内容区又分为高低两个组件
  • 右侧边栏中又蕴含了 3 个子组件

各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需要。

父向子传递

  1. 父组件应用子组件时,自定义属性(属性名任意,属性值为要传递的数据)
  2. 子组件通过 props 接管父组件属性

父组件应用子组件,并自定义了 title 属性:

<div id="app">
    <h1> 打个招呼:</h1>
    <!-- 应用子组件,同时传递 title 属性 -->
    <introduce title="父组件传递的音讯"/>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> Vue.component("introduce",{
        // 间接应用 props 接管到的属性来渲染页面
        template:'<h1>{{title}}</h1>',
        props:['title'] // 通过 props 来接管一个父组件传递的属性
    })
    var app = new Vue({el:"#app"})</script>

传递简单数据

咱们定义一个子组件,并承受简单数据:

 const myList = {
        template: '
        <ul>
         <li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>
        </ul>
        ',
        props: {
            items: {
                type: Array,
                default: [],
                required: true
            }
        }
    };
  • 这个子组件能够对 items 进行迭代,并输入到页面。
  • props:定义须要从父组件中接管的属性

    • items:是要接管的属性名称

      • type:限定父组件传递来的必须是数组
      • default:默认值
      • required:是否必须

咱们在父组件中应用它:

<div id="app">
    <h2> 百知已开设如下课程:</h2>
    <!-- 应用子组件的同时,传递属性,这里应用了 v -bind,指向了父组件本人的属性 lessons -->
    <my-list :items="lessons"/>
</div>
var app = new Vue({
    el:"#app",
    components:{myList // 当 key 和 value 一样时,能够只写一个},
    data:{
        lessons:[{id:1, name: 'java'},
            {id:2, name: 'python'},
            {id:3, name: 'ui'},
        ]
    }
})

子向父的通信

来看这样的一个案例:

<div id="app">
    <h2>num: {{num}}</h2>
    <!-- 应用子组件的时候,传递 num 到子组件中 -->
    <counter :num="num"></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> Vue.component("counter", {// 子组件,定义了两个按钮,点击数字 num 会加或减
        template:'
            <div>
                <button @click="num++"> 加 </button>  
                <button @click="num--"> 减 </button>  
            </div>',
        props:['num']// count 是从父组件获取的。})
    var app = new Vue({
        el:"#app",
        data:{num:0}
    })</script>
  • 子组件接管父组件的 num 属性
  • 子组件定义点击按钮,点击后对 num 进行加或减操作

咱们尝试运行,如同没问题,点击按钮试试:

image-20201001200426862

子组件接管到父组件属性后,默认是不容许批改的。怎么办?

既然只有父组件能批改,那么加和减的操作肯定是放在父组件:

var app = new Vue({
    el:"#app",
    data:{num:0},
    methods:{ // 父组件中定义操作 num 的办法
        increment(){this.num++;},
        decrement(){this.num--;}
    }
})

然而,点击按钮是在子组件中,那就是说须要子组件来调用父组件的函数,怎么做?

咱们能够 通过 v -on 指令将父组件的函数绑定到子组件 上:

<div id="app">
    <h2>num: {{num}}</h2>
    <counter :count="num" @inc="increment" @dec="decrement"></counter>
</div>

在子组件中定义函数,函数的具体实现调用父组件的实现,并在子组件中调用这些函数。当子组件中按钮被点击时,调用绑定的函数:

 Vue.component("counter", {
            template:'
                <div>
                    <button @click="plus"> 加 </button>  
                    <button @click="reduce"> 减 </button>  
                </div>',
            props:['count'],
            methods:{plus(){this.$emit("inc");
                },
                reduce(){this.$emit("dec");
                }
            }
        })
  • vue 提供了一个内置的 this.$emit()函数,用来调用父组件绑定的函数

路由 vue-router

场景模仿

当初咱们来实现这样一个性能:

一个页面,蕴含登录和注册,点击不同按钮,实现登录和注册页切换。

编写父组件

为了让接下来的性能比拟清晰,咱们先新建一个文件夹:src

而后新建一个 HTML 文件,作为入口:index.html

而后编写页面的根本构造:

<div id="app">
    <span> 登录 </span>
    <span> 注册 </span>
    <hr/>
    <div>
        登录页 / 注册页
    </div>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> var vm = new Vue({el:"#app"})</script>

编写登录及注册组件

接下来咱们来实现登录组件,以前咱们都是写在一个文件中,然而为了复用性,开发中都会把组件放入独立的 JS 文件中,咱们新建一个 user 目录以及 login.js 及 register.js。

编写组件,这里咱们只写模板,不写性能。

login.js 内容如下:

const loginForm = {
    template:'
    <div>
    <h2> 登录页 </h2> 
    用户名:<input type="text"><br/>
    明码:<input type="password"><br/>
    </div>
    '
}

register.js 内容:

const registerForm = {
    template:'
    <div>
    <h2> 注册页 </h2> 
    用 &ensp; 户 &ensp; 名:<input type="text"><br/>
    密 &emsp;&emsp; 码:<input type="password"><br/>
    确认明码:<input type="password"><br/>
    </div>
    '
}

在父组件中援用

<div id="app">
    <span> 登录 </span>
    <span> 注册 </span>
    <hr/>
    <div>
        <!--<loginForm></loginForm>-->
        <!--
            疑难:为什么不采纳下面的写法?因为 html 是大小写不敏感的,如果采纳下面的写法,则被认为是 <loginform></loginform>
            所以,如果是驼峰模式的组件,须要把驼峰转化为“-”的模式
         -->
        <login-form></login-form>
        <register-form></register-form>
    </div>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script src="user/login.js"></script>
<script src="user/register.js"></script>
<script type="text/javascript"> var vm = new Vue({
        el: "#app",
        components: {
            loginForm,
            registerForm
        }
    })</script>

问题

咱们期待的是,当点击登录或注册按钮,别离显示登录页或注册页,而不是一起显示。

然而,如何能力动静加载组件,实现组件切换呢?

尽管应用原生的 Html5 和 JS 也能实现,然而官网举荐咱们应用 vue-router 模块。

vue-router 简介和装置

应用 vue-router 和 vue 能够十分不便的实现 简单单页利用的动静路由性能。

官网:https://router.vuejs.org/zh-cn/

应用 npm 装置:npm install vue-router --save

在 index.html 中引入依赖:

<script src="../node_modules/vue-router/dist/vue-router.js"></script>

疾速入门

新建 vue-router 对象,并且指定路由规定:

// 创立 VueRouter 对象
const router = new VueRouter({
    routes:[ // 编写路由规定
        {
            path:"/login", // 申请门路
            component:loginForm // 组件名称
        },
        {path:"/register",component:registerForm},
    ]
})
  • 创立 VueRouter 对象,并指定路由参数
  • routes:路由规定的数组,能够指定多个对象,每个对象是一条路由规定,蕴含以下属性:

    • path:路由的门路
    • component:组件名称

在父组件中引入 router 对象:

var vm = new Vue({
    el:"#app",
    components:{// 援用登录和注册组件
        loginForm,
        registerForm
    },
    router // 援用下面定义的 router 对象
})

页面跳转管制:

<div id="app">
    <!--router-link 来指定跳转的门路 -->
    <span><router-link to="/login"> 登录 </router-link></span>
    <span><router-link to="/register"> 注册 </router-link></span>
    <hr/>
    <div>
        <!--vue-router 的锚点 -->
        <router-view></router-view>
    </div>
</div>
  • 通过 router-view 来指定一个锚点,当路由的门路匹配时,vue-router 会主动把对应组件放到锚点地位进行渲染
  • 通过 router-link 指定一个跳转链接,当点击时,会触发 vue-router 的路由性能。

单文件组件

vue-cli3 开发单文件组件

Vue.component('组件名',{})
new Vue({})
毛病
  • 全局定义组件的名字时不能反复
  • 字符串模板 es6 提供了模板字符串
  • 不反对 css

在 vue 中把.vue 的文件称为 单文件组件

Vue CLI3 脚手架

根本配置
  • 装置 Nodejs

    • 保障 Node.js8.9 或更高版本
    • 终端中输出node -v, 保障已装置胜利
  • 装置淘宝镜像源

    • npm install -g cnpm --registry=https://registry.npm.taobao.org
    • 当前的 npm 能够用 cnpm 代替
  • 装置 Vue Cli3 脚手架

    • cnpm install -g @vue/cli
  • 查看其版本是否正确

    • vue --version

疾速原型开发

在命令行工具 cmd,或者 Intellij IDEA 的 Terminal 中进入想要构建我的项目的目录,输出

vue init webpack project-name 

回车,webpack 默认版本为 2.0。

接下来会呈现几个提醒,别离是输出项目名称、形容、作者等,按理论状况抉择即可。

?Project name ---- 项目名称,init 命令时也填了个 project-name,如果无需更改,间接回车即可;?Project description ---- 我的项目形容,按需填写。无需填写能够间接回车;?Author ---- 作者?Vue build ---- 构建模式,个别默认第一个;?Install vue-router? ---- 是否装置 vue-router。选 Y。后边构建我的项目会用到。?Use ESLint to lint yout code? ---- 格局校验,按需;?Set up unit tests ---- 测试相干,按需;?Setup e2e tests with Nightwatch? ---- 测试相干,按需;?Should we run‘npm install’for you after the project has been created? ---- 按需,这里我选 Yes, use NPM。如果选 No,后续本人在指标 

目录下执行 npm install 即可。这样构建进去的我的项目,能够间接运行。进入我的项目所在目录,执行 npm run dev,执行完看到以下提醒:

Your application is running here: http://localhost:8080

在浏览器关上 http://localhost:8080,看到这个页面,接下来就能够开始开发了。

剖析 Vue 脚手架生成的我的项目构造

​ node_modules: 依赖包目录 ​ public:动态资源目录 ​ src:源码目录 ​ src/assets: 资源目录 ​ src/components:组件目录 ​ src/views: 视图组件目录 ​ src/App.vue: 根组件 ​ src/main.js: 入口 js ​ src/router.js: 路由 js ​ babel.config.js:babel 配置文件

应用单文件组件开发购物车

<template>
  <div id="app">
    <h1>{{title}}</h1>
    <ul>
      <li v-for="item in cartList" :key="item.id">
        <h2>{{item.title}}</h2>
        <p>${{item.price}}</p>
      </li>
    </ul>
    <my-cart :title="title" :cart-list="cartList"></my-cart>
  </div>
</template>
  <script> import  MyCart from './components/Cart';
    export default {
      name:"app",
      data() {
        return {
          cartList:[{id:1,title:"vue 实战",price:188,active:true,count:2},
            {id:2,title:"react 实战",price:288,active:false,count:1}],
          title:"购物车"
        };
      },
      components:{MyCart}
    } </script>

购物车文件代码:

<template>
    <div>
      <h1>{{title}}</h1>
      <table border="1">
        <tr>
          <th>#</th>
          <th> 课程 </th>
          <th> 单价 </th>
          <th> 数量 </th>
          <th> 总价 </th>
        </tr>
        <tr v-for="(c,index) in cartList" :key="c.id">
          <td>
            <input type="checkbox" v-model="c.active">
          </td>
          <td>{{c.title}}</td>
          <td>{{c.price}}</td>
          <td>
            <button @click="substract(index)">-</button>
            {{c.count}}
            <button @click="add(index)">+</button>
          </td>
          <td>¥{{c.price*c.count}}</td>
        </tr>
        <tr>
          <td></td>
          <td colspan="2">{{activeCount}}/{{count}}</td>
          <td colspan="2">¥{{total}}</td>
        </tr>
      </table>
    </div>
</template>
<script> export default {
      name:"cart",
      props:['title','cartList'],
      methods: {remove(i) {if (window.confirm("确定是否要删除?")) {this.cartList.splice(i, 1);
          }
        },
        substract(i) {let count = this.cartList[i].count;
          count > 1 ? (this.cartList[i].count -= 1) : this.remove(i);
        },
        add(i) {this.cartList[i].count++;
        }
      },
      computed:{count(){return this.cartList.length;},
        activeCount(){return this.cartList.filter(v=>v.active).length;
        },
        total(){
          let sum=0;
          this.cartList.forEach(c=>{if(c.active){sum+=c.price*c.count;}
          });
          return sum;
        }
      }
    }</script>
<style scoped>
</style>

Vuejs Ajax

Vuejs 并没有间接解决 ajax 的组件,但能够应用 axios 组件实现对异步申请的操作。

Axios 简介

# 如果应用 npm 则能够如下装置
npm install axios

axios 利用

办法阐明

axios 能够应用的办法有:

  • axios(config)

config 申请配置

这些是创立申请时能够用的配置选项。只有 url 是必须的。如果没有指定 method,申请将 默认应用 get 办法

{
 // `url` 是用于申请的服务器 URL
 url: '/user',
 
 // `method` 是创立申请时应用的办法
 method: 'get', // 默认是 get
 
 // `baseURL` 将主动加在 `url` 后面,除非 `url` 是一个相对 URL。// 它能够通过设置一个 `baseURL` 便于为 axios 实例的办法传递绝对 URL
 baseURL: 'https://some-domain.com/api/',
 
 // `params` 是行将与申请一起发送的 URL 参数
 // 必须是一个无格局对象 (plain object) 或 URLSearchParams 对象
 params: {ID: 12345},
 
 // `data` 是作为申请主体被发送的数据
 // 只实用于这些申请办法 'PUT', 'POST', 和 'PATCH'
 // 在没有设置 `transformRequest` 时,必须是以下类型之一:// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
 // - 浏览器专属:FormData, File, Blob
 // - Node 专属:Stream
 data: {firstName: 'Fred'},
 
 // `timeout` 指定申请超时的毫秒数(0 示意无超时工夫)
 // 如果申请话费了超过 `timeout` 的工夫,申请将被中断
 timeout: 1000
}

响应构造

{
 // `data` 由服务器提供的响应
 data: {},
 
 // `status` 来自服务器响应的 HTTP 状态码
 status: 200,
 
 // `statusText` 来自服务器响应的 HTTP 状态信息
 statusText: 'OK',
 
 // `headers` 服务器响应的头
 headers: {},
 
 // `config` 是为申请提供的配置信息
 config: {}}

axios 办法示例

能够通过向 axios 传递相干配置来创立申请

axios(config)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vuejs 测试 </title>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script src="js/axios.min.js"></script>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(user,index) in users" :key="index">
            {{index}} -- {{user.name}} -- {{user.age}} -- {{user.gender}}
        </li>
    </ul>
</div>
<script type="text/javascript"> var app = new Vue({
        el: "#app",
        data: {users: []
        },
        created() {
            // 初始化加载数据
            axios({
                method: "get",
                url: "data.json"
            }).then((res) => {console.log(res);
                // 将获取数据设置到 users 属性
                // 不能应用 this,在 axios 回调函数中示意窗口,不是 vue 实例
                app.users = res.data;
            }).catch(error => {alert(error);
            })
        }
    });</script>
</body>
</html>

综合案例

购物车综合案例

第一步:实现图书的列表显示

<body>
    <div id="myDiv">
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 价格 </td>
                <td> 购买数量 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="book in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>{{book.price}}</td>
                <td>
                    <button>-</button>
                    {{book.number}}
                    <button>+</button>
                </td>
                <td>
                    <button> 删除 </button>
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                books: [{id: 1, name: '天龙八部', pubDate:'1988-02' ,price: 80.00, number: 1},
                    {id: 2, name: '射雕英雄传', pubDate:'2000-09', price: 20.00, number: 1},
                    {id: 3, name: '倚天屠龙记', pubDate:'1986-12', price: 60.00, number: 1},
                    {id: 4, name: '鹿鼎记', pubDate:'2001-05', price: 70.00, number: 1}
                ]
            }
        }); </script>
</body>

第二步:价格小数问题解决

形式一:methods
<body>
    <div id="myDiv">
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 价格 </td>
                <td> 购买数量 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="book in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>{{getPrice(book.price)}}</td>
                <td>
                    <button>-</button>
                    {{book.number}}
                    <button>+</button>
                </td>
                <td>
                    <button> 删除 </button>
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                books: [{id: 1, name: '天龙八部', pubDate:'1988-02' ,price: 80.01, number: 1},
                    {id: 2, name: '射雕英雄传', pubDate:'2000-09', price: 20.00, number: 1},
                    {id: 3, name: '倚天屠龙记', pubDate:'1986-12', price: 60.00, number: 1},
                    {id: 4, name: '鹿鼎记', pubDate:'2001-05', price: 70.00, number: 1}
                ]
            },
            methods: {getPrice(price){return '¥' + price.toFixed(2);
                }
            }
        }); </script>
</body>
形式二:过滤器
== 能够利用到插值表达式或 v -bind 表达式中,能够做格式化。== 
<body>
    <div id="myDiv">
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 价格 </td>
                <td> 购买数量 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="book in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>{{book.price | getPrice}}</td>
                <td>
                    <button>-</button>
                    {{book.number}}
                    <button>+</button>
                </td>
                <td>
                    <button> 删除 </button>
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                books: [{id: 1, name: '天龙八部', pubDate:'1988-02' ,price: 80.01, number: 1},
                    {id: 2, name: '射雕英雄传', pubDate:'2000-09', price: 20.00, number: 1},
                    {id: 3, name: '倚天屠龙记', pubDate:'1986-12', price: 60.00, number: 1},
                    {id: 4, name: '鹿鼎记', pubDate:'2001-05', price: 70.00, number: 1}
                ]
            },
            filters: {getPrice(price){return '¥' + price.toFixed(2);
                }
            }
        }); </script>
</body>

第三步:数量加减操作

<body>
    <div id="myDiv">
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 价格 </td>
                <td> 购买数量 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="book in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>{{book.price}}</td>
                <td>
                    <button @click="decrement(book)" v-bind:disabled="book.number < 2">
                      -
                   </button>
                    {{book.number}}
                    <button @click="increment(book)">+</button>
                </td>
                <td>
                    <button> 删除 </button>
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                books: [{id: 1, name: '天龙八部', pubDate:'1988-02' ,price: 80.01, number: 1},
                    {id: 2, name: '射雕英雄传', pubDate:'2000-09', price: 20.00, number: 1},
                    {id: 3, name: '倚天屠龙记', pubDate:'1986-12', price: 60.00, number: 1},
                    {id: 4, name: '鹿鼎记', pubDate:'2001-05', price: 70.00, number: 1}
                ]
            },
            methods: {decrement(book){book.number--;},
                increment(book){book.number++;}
            }
        }); </script>
</body>

第四步:移除按钮

<body>
    <div id="myDiv">
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 价格 </td>
                <td> 购买数量 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="(book,index) in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>{{book.price}}</td>
                <td>
                    <button @click="decrement(book)" v-bind:disabled="book.number < 2">-</button>
                    {{book.number}}
                    <button @click="increment(book)">+</button>
                </td>
                <td>
                    <button @click="deleteHandle(index)"> 删除 </button>
                </td>
            </tr>
        </table>
        <h2 v-if="books.length <= 0">
            购物车空洞无物
        </h2>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                books: [{id: 1, name: '天龙八部', pubDate:'1988-02' ,price: 80.01, number: 1},
                    {id: 2, name: '射雕英雄传', pubDate:'2000-09', price: 20.00, number: 1},
                    {id: 3, name: '倚天屠龙记', pubDate:'1986-12', price: 60.00, number: 1},
                    {id: 4, name: '鹿鼎记', pubDate:'2001-05', price: 70.00, number: 1}
                ]
            },
            methods: {deleteHandle(index){this.books.splice(index,1);
                }
            }
        }); </script>
</body>

第五步:计算最终价格

<body>
    <div id="myDiv">
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 价格 </td>
                <td> 购买数量 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="(book,index) in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>{{book.price}}</td>
                <td>
                    <button @click="decrement(book)" v-bind:disabled="book.number < 2">-</button>
                    {{book.number}}
                    <button @click="increment(book)">+</button>
                </td>
                <td>
                    <button @click="deleteHandle(index)"> 删除 </button>
                </td>
            </tr>
        </table>
        <h1> 总价:{{totalPrice | getPrice}}</h1>
        <h2 v-if="books.length <= 0">
            购物车空洞无物
        </h2>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                books: [{id: 1, name: '天龙八部', pubDate:'1988-02' ,price: 80.01, number: 1},
                    {id: 2, name: '射雕英雄传', pubDate:'2000-09', price: 20.00, number: 1},
                    {id: 3, name: '倚天屠龙记', pubDate:'1986-12', price: 60.00, number: 1},
                    {id: 4, name: '鹿鼎记', pubDate:'2001-05', price: 70.00, number: 1}
                ]
            },
            filters: {getPrice(price){return '¥' + price.toFixed(2);
                }
            },
            computed: {totalPrice(){return this.books.reduce((sum,book)=>{return sum  + book.price;},0)
                }
            }
        }); </script>
</body>

图书治理综合案例

第一步:实现列表、新增和删除

<body>
    <div id="myDiv">
        id: <input type="text" v-model="id"/>
        图书名称: <input type="text" v-model="name"/>
        <button @click="add"> 增加 </button>
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="(book,index) in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>
                    <a href=""@click.prevent="deleteHandle(index)"> 删除 </a> // 阻止事件默认行为
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                id: '',
                name: '',
                books: [{id: 1, name: '天龙八部', pubDate: new Date()},
                    {id: 2, name: '射雕英雄传', pubDate: new Date()},
                ]
            },
            methods: {add(){let book = {id:this.id, name:this.name , pubDate:new Date()};
                    this.books.push(book);
                },
                deleteHandle(index){this.books.splice(index,1);
                }
            }
        }); </script>
</body>

第二步:实现搜寻筛选

<body>
    <div id="myDiv">
        id: <input type="text" v-model="id"/>
        图书名称: <input type="text" v-model="name"/>
        <button @click="add"> 增加 </button>
        依据图书名称搜寻:<input type="text" v-model="kw"/>
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="(book,index) in search(kw)">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>
                    <a href=""@click.prevent="deleteHandle(index)"> 删除 </a>
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                id: '',
                name: '',
                kw: '',
                books: [{id: 1, name: '天龙八部', pubDate: new Date()},
                    {id: 2, name: '射雕英雄传', pubDate: new Date()},
                ]
            },
            methods: {add(){let book = {id:this.id, name:this.name , pubDate:new Date()};
                    this.books.push(book);
                },
                search(kw){let result = [];
                    this.books.forEach((item)=>{if (item.name.includes(kw)){result.push(item);
                        }
                    });
                    return result;
                }
            }
        }); </script>
</body>
== 换种形式实现:== 
search(kw){return this.books.filter((item)=>{return item.name.includes(kw);
    })
}

第三步:日期格式化

<body>
    <div id="myDiv">
        id: <input type="text" v-model="id"/>
        图书名称: <input type="text" v-model="name"/>
        <button> 增加 </button>
        依据图书名称搜寻:<input type="text" v-model="kw"/>
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="(book,index) in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate | dateFormat}}</td>
                <td>
                    <a href=""> 删除 </a>
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script src="../js/moment.js"></script>
    <script type="text/javascript"> Vue.filter("dateFormat",(value)=>{return moment(value).format("YYYY-MM-DD");
        });
        const app = new Vue({
            el: "#myDiv",
            data: {
                id: '',
                name: '',
                kw: '',
                books: [{id: 1, name: '天龙八部', pubDate: new Date()},
                    {id: 2, name: '射雕英雄传', pubDate: new Date()},
                ]
            }
        }); </script>
</body>

第四步:优化增加性能

== 需要:下面的案例中,咱们须要点击增加按钮实现增加一本书,有时候是这样子的,咱们按下回车键也能够增加,上面就来做这个性能。== 
按下 enter 键实现增加形式 1
图书名称: <input type="text" v-model="name" @keyup.enter="add"/>  // 可行
按下 enter 键实现增加形式 2
图书名称: <input type="text" v-model="name" @keyup.13="add"/>  // 键码可行
按下 F2 键实现增加形式 1
图书名称: <input type="text" v-model="name" @keyup.f2="add"/> // 可行,低版本不可行
按下 F2 键实现增加形式 2
图书名称: <input type="text" v-model="name" @keyup.113="add"/> // 可行,通过键码代表 F2 可行
按下 F2 键盘实现增加形式 3

== 通过键码代表 F2 可行,然而浏览性不好,能够自定义按键修饰符,次要是解决低版本 Vue 的问题。==

图书名称: <input type="text" v-model="name" @keyup.f2="add"/>
Vue.config.keyCodes.f2 = 113

第五步:页面关上的时候就搜寻框取得焦点

依据图书名称搜寻:<input type="text" v-model="kw" v-focus/>
Vue.directive("focus",{inserted: function(el){el.focus();
    }
});

第五步:实现批改性能

<body>
    <div id="myDiv">
        id: <input type="text" v-model="id" :disabled="disable"/>
        图书名称: <input type="text" v-model="name"/>
        <button @click="handle"> 提交 </button>
        依据图书名称搜寻:<input type="text" v-model="kw"/>
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="(book,index) in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>
                    <a href=""@click.prevent="update(book.id)"> 批改 </a>
                    <a href=""> 删除 </a>
                </td>
            </tr>
        </table>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                id: '',
                name: '',
                kw: '',
                disable: false,
                books: [{id: 1, name: '天龙八部', pubDate: new Date()},
                    {id: 2, name: '射雕英雄传', pubDate: new Date()},
                ]
            },
            methods: {
                // 增加和批改重用
                handle(){if(this.disable){
                        // 为 true, 就示意批改
                        this.books.forEach((item)=>{if(item.id == this.id){
                                item.name = this.name;
                                return item;
                            }
                        });
                        // 批改结束之后还须要对 disable 设置为 true 示意容许增加
                        this.disable = false;
                        this.id = "";
                        this.name = "";
                    }else{
                        // 就示意增加
                        let book = {id:this.id, name:this.name , pubDate:new Date()};
                        this.books.push(book);
                    }
                },
                update(bookId){
                    // 0、禁止批改 id 文本框
                    this.disable = true;
                    // 1、依据 bookId 查找出要编辑的图书
                    let book = this.books.filter((item)=>{return item.id == bookId;});
                    // 2、把获取到的图书填充到表单中
                    this.id = book[0].id;
                    this.name = book[0].name;
                }
            }
        }); </script>
</body>

第六步:应用计算属性统计图书品种

<h1> 总共有 {{totalCount}} 种不同品种的书 </h1>
computed: {totalCount(){return this.books.length;}
}

第七步:不能增加反复的图书【监听器】

<body>
    <div id="myDiv">
        id: <input type="text" v-model="id" :disabled="disable"/>
        图书名称: <input type="text" v-model="name"/>
        <button @click="handle" :disabled="flag"> 提交 </button>
        依据图书名称搜寻:<input type="text" v-model="kw"/>
        <table border="1">
            <tr>
                <td> 图书编号 </td>
                <td> 图书名称 </td>
                <td> 出版日期 </td>
                <td> 操作 </td>
            </tr>
            <tr v-for="(book,index) in books">
                <td>{{book.id}}</td>
                <td>{{book.name}}</td>
                <td>{{book.pubDate}}</td>
                <td>
                    <a href=""@click.prevent="update(book.id)"> 批改 </a>
                    <a href=""> 删除 </a>
                </td>
            </tr>
        </table>
        <h1> 总共有 {{totalCount}} 种不同品种的书 </h1>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript"> const app = new Vue({
            el: "#myDiv",
            data: {
                id: '',
                name: '',
                kw: '',
                disable: false,
                flag: false,
                books: [{id: 1, name: '天龙八部', pubDate: new Date()},
                    {id: 2, name: '射雕英雄传', pubDate: new Date()},
                ]
            },
            computed: {totalCount(){return this.books.length;}
            },
            methods: {
                // 增加和批改重用
                handle(){if(this.disable){
                        // 为 true, 就示意批改
                        this.books.forEach((item)=>{if(item.id == this.id){
                                item.name = this.name;
                                return item;
                            }
                        });
                        // 批改结束之后还须要对 disable 设置为 true 示意容许增加
                        this.disable = false;
                        this.id = "";
                        this.name = "";
                    }else{
                        // 就示意增加
                        let book = {id:this.id, name:this.name , pubDate:new Date()};
                        this.books.push(book);
                    }
                },
                update(bookId){
                    // 0、禁止批改 id 文本框
                    this.disable = true;
                    // 1、依据 bookId 查找出要编辑的图书
                    let book = this.books.filter((item)=>{return item.id == bookId;});
                    // 2、把获取到的图书填充到表单中
                    this.id = book[0].id;
                    this.name = book[0].name;
                }
            },
            watch:{name(value){
                    let result = false;
                    this.books.forEach((item)=>{if (item.name == value){
                            result = true;
                            return;
                        }
                    })
                    if (result){console.log("11");
                        this.flag = true;
                    }else{this.flag = false;}
                }
            }
        }); </script>
</body>

第八步:图书数据的初始化

mounted(){
    // 模仿 ajax 申请获取数据
    let result = [{id: 1, name: '天龙八部', pubDate: new Date()},
                {id: 2, name: '射雕英雄传', pubDate: new Date()}
                ];
    this.books = result;
},
退出移动版