Vue快速入门
一、Vue快速入门
2008年,google的Chrome发布,随后就以极快的速度占领市场,超过IE成为浏览器市场的主导者。
2009年,Ryan Dahl在谷歌的Chrome v8引擎基础上,打造了基于事件循环的异步IO框架:Node.js。
基于时间循环的异步lO
单线程运行,避免多线程的变量同步问题
JS可以编写后台diamante,前后台统━编程语言
node.js的伟大之处不在于让JS迈向了后端开发,而是构建了一个庞大的生态系统。
2010年,NPM作为node.js的包管理系统首次发布,开发人员可以遵循Common.js规范来编写Node.js模块,然后发布到NPM上供其他开发人员使用。
目前已经是世界最大的包模块管理系统。
随后,在node的基础上,涌现出了一大批的前端框架:
MVVM模式
M:即Model,模型,包括数据和一些基本操作
V:即View,视图,页面渲染结果
VM:即View-Model,模型与视图间的双向操作(无需开发人员干涉)
在MWM之前,开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。
而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中。
而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model和View之间是如何互相影响的:
●只要我们Model发生了改变,View上自然就会表现出来。
●当用户修改了View,Model中的数据也会跟着改变。
把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上。
而我们今天要学习的,就是一款MVVM模式的框架:Vue
1、认识Vue
Wue(读音/vju:/,类似于view)是一套用于构建用户界面的渐进式框架。
与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。
Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
另一方面,当与现代化的工县摄以及各种支持啦库结合使用时,Vue也完全能够为复杂的单页应用提供驱动.
2、安装Node.js
(1)进入Node.js官网https://nodejs.org/zh-cn/
然后install安装即可
安装完成
控制台测试
输入node-v
然后回车
2、NPM
npm版本输入npm -v
然后回车
npm默认的仓库地址是在国外网站,速度较慢,建议大家设置到淘宝镜像。
但是切换镜像是比较麻烦的正-推荐切换镜像的工具:nrm
我们首先安装nrm,这里-g代表全局安装
npm install nrm -g
输入:nrm ls报错
找到该文件C:\Users\ZHENG\AppData\Roaming\npm\node_modules\nrm
//const NRMRC = path.join(process.env.HOME, '.nrmrc'); (删除)
const NRMRC = path.join(process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'], '.nrmrc');
继续输入nrm ls
切换淘宝镜像nrm use taobao
测试一下nrm test taobao
二、工程案例
1、创建工程
2、安装Vue
在IDEA的终端当中
在终端上输入:npm init -y
报错
(1)初始化项目
npm init -y
(2)安装Vue
只再当前项目安装Vue:npm install vue --save
打开下面内容证明安装完成
3、创建HTML文件
(1)编写基本的HTML页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1>
xxx非常美丽!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
</script>
</body>
</html>
运行查看一下
(2)使用Vue
a、定义属性
首先通过new Vue()
来创建Vue实例
然后构造函数接收一个对象,对象中有一些属性:
el
:是element
的缩写,通过id
选中要渲染的页面元素,本例中是一个div
data
:数据,数据是一个对象,里面有很多属性,都可以渲染到视图中name
:这里我们指定了一个name
属性
页面中的h2
元素中,我们通过{{name)}
的方式,来渲染刚刚定义的name
属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1>
{{name}} xxx非常美丽!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"虎哥"
}
});
</script>
</body>
</html>
运行测试
在谷歌浏览器控制台
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"虎哥",
num: 1,
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="num" />
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"虎哥",
num: 1,
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"虎哥",
num: 1,
}
});
</script>
</body>
</html>
b、定义属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"虎哥",
num: 1,
},
methods : {
handleClick(){
console.log("hello");
}
}
});
</script>
</body>
</html>
三、Vue生命周期(钩子)
每个Vue实例在被创建时都要经过一系列的初始化过程︰
创建实例,装载模板,渲染模板等等。Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。
每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用。
1、生命周期:
2、渲染数据:钩子函数
例如: created代表在vue实例创建后;
我们可以在Vue中定义一个created函数,代表这个时期的构造函数;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "虎哥";
}
});
</script>
</body>
</html>
3、模拟实际渲染数据:this 我们可以看下在vue内部的this变量是谁,我们在created的时候,打印this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
setTimeout(() => this.name = "虎哥 真的",1000)
}
});
</script>
</body>
</html>
延时一秒
总结: this就是当前的Vue实例,在Vue对象内部,必须使用this才能访问到Vue中定义的data内属性、方法等。
四、指令
什么是指令?
指令(Directives)是带有 v-前缀的特殊属性。
例如我们在入门案例中的v-model,代表双向绑定。
1、插值表达式
(1)花括号
格式:
{{表达式}}
说明;
- 该表达式支持JS语法,可以调用js内置函数(必须有返回值)
- 表达式必须有返回结果。例如1+1,没有结果的表达式不允许使用,如: var a = 1+1;
- 可以直接获取Vue实例中定义的数据或函数
示例
HTML:
<div id= " app">i{name ) )</div>
JS:
var app =new vue({
el:"#app",
data:{
name:"Jack""
}
})
2、差值闪烁
使用0方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的
{{}}
加载完毕后才显示正确数据,我们称为插值闪烁。
我们将网速调慢一些,然后试试看刚才的案例:
刷新页面有延迟
3、使用v-text和v-html
使用v-text
和v-html
指令来替代{{}}说明:
v-text
∶将数据输出到元素内部,如果输出的数据有
代码,会作为普通文本输出
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "虎哥 真的",1000;
}
});
</script>
</body>
</html>
运行测试
v-html
:将数据输出到元素内部,如果输出的数据有HTML代码,会被渲染
从上述结果当中似乎没有什么区别
以下继续修改代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
v-text
:将数据输出到元素内部,如果输出的数据有HTML代码,会作为普通文本输出
v-html
:将数据输出到元素内部,如果输出的数据有HTML代码,会被渲染
4、v-model
刚才的v-text和v-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>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
<hr/>
<h1>编程语言分类</h1>
<input type="checkbox" v-model="lessons" value="Java" />Java <br/>
<input type="checkbox" v-model="lessons" value="JavaScript" />JavaScript <br/>
<input type="checkbox" v-model="lessons" value="Python" />Python <br/>
<h1>
您已购买下列课程:{{lessons.join(",")}}
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
lessons: []
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
运行查看
5、v-on
(1)基本用法
v-on指令用于给页面元素绑定事件。
语法:
v-on:事件名="js片段或函数名"
简写语法:
真
@事件名="js片段或函数名“
例如v-on:click='add'
可以简写为@click='add'
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<button @click="decrement">-</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
<hr/>
<h1>编程语言分类</h1>
<input type="checkbox" v-model="lessons" value="Java" />Java <br/>
<input type="checkbox" v-model="lessons" value="JavaScript" />JavaScript <br/>
<input type="checkbox" v-model="lessons" value="Python" />Python <br/>
<h1>
您已购买下列课程:{{lessons.join(",")}}
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
lessons: []
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
},
decrement(){
this.num--;
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
(2)点击事件(包含关系(冒泡))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<button @click="decrement">-</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
<hr/>
<h1>编程语言分类</h1>
<input type="checkbox" v-model="lessons" value="Java" />Java <br/>
<input type="checkbox" v-model="lessons" value="JavaScript" />JavaScript <br/>
<input type="checkbox" v-model="lessons" value="Python" />Python <br/>
<h1>
您已购买下列课程:{{lessons.join(",")}}
</h1>
<hr/>
<!--v-on-->
<div style="width: 100px; height: 100px; background-color:indianred; " @click="print('div')">
div
<button @click="print('button')">点我试试</button>
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
lessons: []
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
},
decrement(){
this.num--;
},print(msg){
console.log(msg)
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
点击内部同时触发两个
点击外面触发一个事件
(3)点击事件(设置不自动包含关系(停止冒泡))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<button @click="decrement">-</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
<hr/>
<h1>编程语言分类</h1>
<input type="checkbox" v-model="lessons" value="Java" />Java <br/>
<input type="checkbox" v-model="lessons" value="JavaScript" />JavaScript <br/>
<input type="checkbox" v-model="lessons" value="Python" />Python <br/>
<h1>
您已购买下列课程:{{lessons.join(",")}}
</h1>
<hr/>
<!--v-on-->
<div style="width: 100px; height: 100px; background-color:indianred; " @click.stop="print('div')">
div
<button @click.stop="print('button')">点我试试</button>
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
lessons: []
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
},
decrement(){
this.num--;
},print(msg){
console.log(msg)
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
现在这种情况只需要添加一个即可
(4)事件修饰符
在事件处理程序中调用event.preventDefault()
或event.stopPropagation())
是非常常见的需求。
尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理DOM事件细节。
为了解决这个问题,Vue.js 为v-on提供了事件修饰符。
之前提过,修饰符是由点开头的指令后缀来表示的
- stop ︰阻止事件冒泡
- prevent :阻止默认事件发生
- capture :使用事件捕获模式
- self∶只有元素自身触发事件才执行。(冒泡或捕获的都不执行)
- once:只执行一次
(5)阻止默认事件发生
阻止a标签跳转
<a href="http://www.baidu.com" @click.prevent="print('百度')">百度一下,你就疯了!</a>
7、v-for
遍历数据渲染页面是非常常用的需求,Vue中通过v-for指令来实现。
(1)遍历数组
语法:
v-for="item in items ""
- items:要遍历的数组,需要在vue的data中定义好。
- item:迭代得到的数组元素的别名
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<button @click="decrement">-</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
<hr/>
<h1>编程语言分类</h1>
<input type="checkbox" v-model="lessons" value="Java" />Java <br/>
<input type="checkbox" v-model="lessons" value="JavaScript" />JavaScript <br/>
<input type="checkbox" v-model="lessons" value="Python" />Python <br/>
<h1>
您已购买下列课程:{{lessons.join(",")}}
</h1>
<hr/>
<!--v-on-->
<div style="width: 100px; height: 100px; background-color:indianred; " @click="print('div')">
div
<button @click.stop="print('button')">点我试试</button>
</div>
<a href="http://www.baidu.com" @click.prevent="print('百度')">百度一下,你就疯了!</a>
<hr>
<!--v-for-->
<ul>
<li v-for="u in users">
{{u.name + "," + u.gender + ","+ u.age }}
</li>
</ul>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
lessons: [],
users:[
{name:'柳岩',gender:'女',age:21},
{name:'虎哥',gender:'男',age:30},
{name:'范冰冰',gender:'女',age:24},
{name:'刘亦菲',gender:'女',age:18},
{name:'古力娜扎',gender:'女',age:25}
]
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
},
decrement(){
this.num--;
},print(msg){
console.log(msg)
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
运行结果
(2)遍历数组:多个参数(数组角标)
在遍历的过程中,如果我们需要知道数组角标,可以指定第二个参数:
语法
v-for=" (item, index) in items "
- items:要迭代的数组
- item:迭代得到的数组元素别名
- index:迭代到的当前元素索引,从0开始。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<button @click="decrement">-</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
<hr/>
<h1>编程语言分类</h1>
<input type="checkbox" v-model="lessons" value="Java" />Java <br/>
<input type="checkbox" v-model="lessons" value="JavaScript" />JavaScript <br/>
<input type="checkbox" v-model="lessons" value="Python" />Python <br/>
<h1>
您已购买下列课程:{{lessons.join(",")}}
</h1>
<hr/>
<!--v-on-->
<div style="width: 100px; height: 100px; background-color:indianred; " @click="print('div')">
div
<button @click.stop="print('button')">点我试试</button>
</div>
<a href="http://www.baidu.com" @click.prevent="print('百度')">百度一下,你就疯了!</a>
<hr>
<!--v-for-->
<ul>
<li v-for="(u,i) in users">
{{i}} {{u.name + "," + u.gender + ","+ u.age }}
</li>
</ul>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
lessons: [],
users:[
{name:'柳岩',gender:'女',age:21},
{name:'虎哥',gender:'男',age:30},
{name:'范冰冰',gender:'女',age:24},
{name:'刘亦菲',gender:'女',age:18},
{name:'古力娜扎',gender:'女',age:25}
]
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
},
decrement(){
this.num--;
},print(msg){
console.log(msg)
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
(3)遍历对象
<ul>
<li v-for="u in users[0]">
{{u}}
</li>
</ul>
(4)遍历对象:多个参数
<ul>
<li v-for="(u,i) in users[0]">
{{u + "," + i }}
</li>
</ul>
<ul>
<li v-for="(v,k,i) in users[0]">
{{i +"_"+ v + "," + k }}
</li>
</ul>
(5)遍历数字
<ul>
<li v-for="i in 5">
{{i}}
</li>
</ul>
8、key
当Vue.js用v-for
正在更新已渲染过的元素列表时,它默认用"就地复用"策略。
如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
这个功能可以有效的提高渲染的效率。
但是要实现这个功能,你需要给Vue
一些提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素
你
需要为每项提供一个唯一 key
属性。理想的key值是每项都有的且唯一的id
。
提升加载数据的速度
<!--v-for-->
<ul>
<li v-for="(u,i) in users" :key="u.name">
{{i}} {{u.name + "," + u.gender + ","+ u.age }}
</li>
</ul>
绑定数组的角标
<!--v-for-->
<ul>
<li v-for="(u,i) in users" :key="i">
{{i}} {{u.name + "," + u.gender + ","+ u.age }}
</li>
</ul>
9、v-if和v-show
v-if,顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。
语法:
v-if”布尔表达式”
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<button @click="decrement">-</button>
<h1>
<span v-text="name"></span> xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
<span v-text="name"></span><br>
<span v-html="name"></span>
<hr/>
<h1>编程语言分类</h1>
<input type="checkbox" v-model="lessons" value="Java" />Java <br/>
<input type="checkbox" v-model="lessons" value="JavaScript" />JavaScript <br/>
<input type="checkbox" v-model="lessons" value="Python" />Python <br/>
<h1>
您已购买下列课程:{{lessons.join(",")}}
</h1>
<hr/>
<!--v-on-->
<div style="width: 100px; height: 100px; background-color:indianred; " @click="print('div')">
div
<button @click.stop="print('button')">点我试试</button>
</div>
<a href="http://www.baidu.com" @click.prevent="print('百度')">百度一下,你就疯了!</a>
<hr>
<!--v-for-->
<ul>
<li v-for="(u,i) in users" :key="i">
{{i}} {{u.name + "," + u.gender + ","+ u.age }}
</li>
</ul>
<ul>
<li v-for="(v,k,i) in users[0]">
{{i +"_"+ v + "," + k }}
</li>
</ul>
<ul>
<li v-for="i in 5">
{{i}}
</li>
</ul>
<hr/>
<!--v-if-->
<button @click="show != show">点击切换</button><br>
<h1 v-if="show">
你好
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
lessons: [],
users:[
{name:'柳岩',gender:'女',age:21},
{name:'虎哥',gender:'男',age:30},
{name:'范冰冰',gender:'女',age:24},
{name:'刘亦菲',gender:'女',age:18},
{name:'古力娜扎',gender:'女',age:25}
],
show: true,
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
},
decrement(){
this.num--;
},print(msg){
console.log(msg)
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "<font color='#8a2be2'>虎哥<font>";
}
});
</script>
</body>
</html>
在页面上
点击以后你好消失(点击后触发事件将show改为false)
10、v-if与v-for结合以及v-else
(1)v-if
当v-if和v-for出现在一起时,v-for优先级更高。
也就是说,会先遍历,再判断条件。
示例:
<ul>
<li v-for="i in 5" v-if="i%2 === 0" >
{{i}}
</li>
</ul>
(2)v-else
<ul>
<li v-for="i in 5">
<span v-if="i%2 === 0">偶数: {{i}} </span>
<span v-else style="background-color:#cccccc;">奇数: {{i}} </span><br>
</li>
</ul>
11、v-show
对比v-if和v-show
<h1 v-if="show">
你好
</h1>
<h1 v-show="show">
你很好,我记住了!
</h1>
运行效果
消失
上述从外表看起来没有什么区别
但是打开检查我们发现
点击之前
点击之后,发现v-if是直接删除结点而v-show是设置style属性display:none隐藏属性
12、v-bind
(1)创建新的HTML页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
}
});
</script>
</body>
</html>
(2)编写CSS样式和HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<button>红色</button>
<button>蓝色</button>
<div id="box" class="red">
我是盒子
我是盒子
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
}
});
</script>
</body>
</html>
(3)添加点击切换图片的事件
a、按照上述正常的解决思维是用差值表达式是这样解决的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.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 id="box" class="{{color}}">
我是盒子
我是盒子
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
color:"red",
}
});
</script>
</body>
</html>
但是事实上上述做法是错误的
差值表达式不可以使用在属性当中
b、上述解决方式是错误的,下面代码使用v-bind
修改上述代码
c、继续更新上述代码 v-bind:class属性的特殊用法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<button @click="isRed=!isRed">点我切换颜色</button>
<div id="box" :class="{red:isRed, blue:!isRed}" >
我是盒子
我是盒子
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
isRed:true
}
});
</script>
</body>
</html>
13、计算属性
在插值表达式中使用js表达式是非常方便的,而且也经常被用到。
但是如果表达式的内容很长,就会显得不够优雅,而且后期维护起来也不方便
例如下面的场景、我们有一个日期的数据,但是是毫秒值:
(a)日期的格式化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<!--class属性-->
<button @click="isRed=!isRed">点我切换颜色</button>
<div id="box" :class="{red:isRed, blue:!isRed}" >
我是盒子
我是盒子
</div>
<!--计算属性-->
<h1>
您的生日:{{ birth }}
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
isRed:true,
birthday : 1529032123201 //毫秒值
},
computed:{
birth(){
const day = new Date(this.birthday);
return day.getFullYear() + "年" + day.getMinutes() +"月" + day.getDay() + "日";
}
}
});
</script>
</body>
</html>
14、watch
(1)监控
watch可以让我们监控一个值的变化,从而做出相应的反应。
自动监控
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<!--class属性-->
<button @click="isRed=!isRed">点我切换颜色</button>
<div id="box" :class="{red:isRed, blue:!isRed}" >
我是盒子
我是盒子
</div>
<!--计算属性-->
<h1>
您的生日:{{ birth }}
</h1>
<!--watch-->
<input type="text" v-model="num" />
<h1>num:{{ num }}</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
isRed:true,
birthday : 1529032123201, //毫秒值
num : 1,
},
computed:{
birth(){
const day = new Date(this.birthday);
return day.getFullYear() + "年" + day.getMinutes() +"月" + day.getDay() + "日";
}
}
});
</script>
</body>
</html>
(2)浅监控
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<!--class属性-->
<button @click="isRed=!isRed">点我切换颜色</button>
<div id="box" :class="{red:isRed, blue:!isRed}" >
我是盒子
我是盒子
</div>
<!--计算属性-->
<h1>
您的生日:{{ birth }}
</h1>
<!--watch-->
<input type="text" v-model="num" />
<h1>num:{{ num }}</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
isRed:true,
birthday : 1529032123201, //毫秒值
num : 1,
},
computed:{
birth(){
const day = new Date(this.birthday);
return day.getFullYear() + "年" + day.getMinutes() +"月" + day.getDay() + "日";
}
},
watch:{
num(newVal,oldVal){
console.log(newVal,oldVal);
}
}
});
</script>
</body>
</html>
运行
newVal 是最新的值 oldVal是旧的值
(3)深监控,监控对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<!--class属性-->
<button @click="isRed=!isRed">点我切换颜色</button>
<div id="box" :class="{red:isRed, blue:!isRed}" >
我是盒子
我是盒子
</div>
<!--计算属性-->
<h1>
您的生日:{{ birth }}
</h1>
<!--watch-->
<input type="text" v-model="num" />
<h1>num:{{ num }}</h1>
<input type="text" v-model="person.age" />
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
isRed:true,
birthday : 1529032123201, //毫秒值
num : 1,
person:{
name:"Jack",
age : 21
}
},
computed:{
birth(){
const day = new Date(this.birthday);
return day.getFullYear() + "年" + day.getMinutes() +"月" + day.getDay() + "日";
}
},
watch:{
num(newVal,oldVal){
console.log(newVal,oldVal);
},
person:{
deep:true,
handler(val){
console.log(val.age)
}
}
}
});
</script>
</body>
</html>
五、组件化
在大型应用开发的时候,页面可以划分成很多部分。
往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。
但是如果每个页面都独白开发,这无骚增加了我们开发的成本。
所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
1、定义安全组件
我们通过Vue的component方法来定义一个全局组件。
创建一个新的页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<counter></counter>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
//定义全局组件,两个参数:1.组件名称2.组件参数
Vue.component("counter",{
template:"<button @click='count++'>点我试试{{ count }}我记住你了!</button>",
data(){
return{
count :0
}
}
}) ;
var app = new Vue({
el:"#app"
})
</script>
</body>
</html>
2、组件的复用
定义好的组件,可以任意复用多次:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--使用定义好的全局组件-->
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
//定义全局组件,两个参数:1.组件名称2.组件参数
Vue.component("counter",{
template:"<button @click='count++'>点我试试{{ count }}我记住你了!</button>",
data(){
return{
count :0
}
}
}) ;
var app = new Vue({
el:"#app"
})
</script>
</body>
</html>
组件的data属性必须是函数!
当我们定义这个 <counter>
组件时,它的data 并不是像这样直接提供一个对象:
data: {
count: 0
}
取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () {
return {
count: 0
}
}
如果 Vue 没有这条规则,点击一个按钮就会影响到其它所有实例!
3、局部注册
一旦局部注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。
因此,对于一些并不频繁使用的组件,我们会采用局部注册。
我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--使用定义好的全局组件-->
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
//定义全局组件,两个参数:1.组件名称2.组件参数
const counter = {
template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
data(){
return {
count:0
}
}
};
var app = new Vue({
el:"#app",
comments:{
counter:counter //将定义的对象注册为组件
}
})
</script>
</body>
</html>
- components就是当前vue对象子组件集合。
其key就是子组件名称
其值就是组件对象的属性 - 效果与刚才的全局注册是类似的,不同的是,这个counter组件只能在当前的Vue实例中使用
4、组件通信
通常一个单页应用会以一棵嵌套的组件树的形式来组织:
- 页面首先分成了顶部导航,左侧内容区,
- 左侧内容区又分为上下两个组件
- 右侧边栏中又包含了3个子组件
各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求。
(1)父向子传递:props
比如我们有一个子组件:
Vue.component("introduce",{
// 直接使用props接收到的属性来渲染页面
template:'<h3>{{title}}</h3>',
props:[title] // 通过props来接收一个父组件传递的属性
})
- 这个子组件中要使用title属性渲染页面,但是自己并没有title属性
- 通过props来接收父组件属性,名为title
父组件使用子组件,同时传递title属性:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1>打个招呼:</h1>
<!--使用子组件,同时传递title属性-->
<introduce title="大家好,我是虎哥"/>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
//定义全局组件,两个参数:1.组件名称2.组件参数
Vue.component("introduce",{
//直接使用props接收到属性来渲染页面
template:'<h3>{{ title }}</h3>',
props:['title'] //通过props来接收一个父组件传递属性
})
var app = new Vue({
el:"#app"
})
</script>
</body>
</html>
(2)传递复杂数据
我们定义一个子组件:
const myList = {
template:'\
<ul>\
<li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
</ul>\
',
props:{ // 通过props来接收父组件传递来的属性
items:{// 这里定义items属性
type:Array,// 要求必须是Array类型
default:[] // 如果父组件没有传,那么给定默认值是[]
}
}
}
- 这个子组件可以对 items 进行迭代,并输出到页面。
- 但是组件中并未定义items属性。
- 通过props来定义需要从父组件中接收的属性
- items:是要接收的属性名称
- type:限定父组件传递来的必须是数组,否则报错
- default:默认值
- items:是要接收的属性名称
我们在父组件中使用它:
全部代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>课程:</h2>
<!-- 使用子组件的同时,传递属性,这里使用了v-bind,指向了父组件自己的属性lessons -->
<my-list :items="lessons"/>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const myList = {
template: '\
<ul>\
<li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
</ul>\
',
props:{ // 通过props来接收父组件传递来的属性
items:{ // 这里定义items属性
type:Array, // 要求必须是Array类型
default:[] // 如果父组件没有传,那么给定默认值是[]
}
}
}
var app = new Vue({
el:"#app",
components:{
myList//当key和value一样的时候,可以只写一个
},
data:{
lessons:[
{id:1, name: 'java'},
{id:2, name: 'php'},
{id:3, name: 'ios'},
]
}
})
</script>
</body>
</html>
(3)子向父通信
来看这样一个案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>num:{{ num }}</h2>
<!-- 使用子组件的同时,传传递num到子组件当中 -->
<counter :num="num"></counter>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
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>
</body>
</html>
- 子组件接收父组件的num属性
- 子组件定义点击按钮,点击后对num进行加或减操作
我们尝试运行:
子组件接收到父组件属性后,默认是不允许修改的。怎么办?
既然只有父组件能修改,那么加和减的操作一定是放在父组件
var app = new Vue({
el:"#app",
data:{
num:0
},
methods:{ // 父组件中定义操作num的方法
increment(){
this.num++;
},
decrement(){
this.num--;
}
}
})
全部代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>num: {{num}}</h2>
<counter :count="num" @inc="increment" @dec="decrement"></counter>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
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");
}
}
})
var app = new Vue({
el:"#app",
data:{
num:0
},
methods:{ // 父组件中定义操作num的方法
increment(){
this.num++;
},
decrement(){
this.num--;
}
}
})
</script>
</body>
</html>
但是,点击按钮是在子组件中,那就是说需要子组件来调用父组件的函数,怎么做?
我们可以通过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函数,用来调用父组件绑定的函数
效果: