简单来说,Vue是针对Javascript提供的一套MVVM框架,该框架可以让我们布局与视图分离,减少数据泥团,同时也是组件开发较实用的一套框架,如果你之前学习过Android的DataBinding框架,可以尝试将思维进行沿用。话不多说,接下来介绍该框架如何使用:
1.下载源代码
首先可以在github上找到托管的代码,也可以通过官网进行了解,建议读者先学习本套课程,再通过官网继续深入学习。
1.打开官网,点击导航上的教程
2.点击tab页面左边的 安装
3.这里介绍了如果安装,你可以将vue.js直接另存为保存起来,也可以通过mpn命令下载
npm install vue
4.下载成功后,会出现一个 node_modules文件夹,将/vue/dist/vue.js(和vue.min.js)复制到我们的项目中。
2.新建项目引入开发包
这里我使用的是WebStorm进行开发的。我的项目目录如下:
3.vue的原理
vue最的核心是ViewModel,他的示意图如下:
上面的示意图主要分为三部分:
DOM:它指代的是Html标签形成的Dom树。也就是每次标签都是Dom的一个环节,操作Dom即是操作Html的视图区。
JavaScript Objects:代表的是data数据。
Vue:也是我们的核心,称之为ViewModel。一般视图区与数据直接混合很容易造成数据混乱,所以你可以认为ViewModel相当于两者的桥梁。数据的变化会导致视图的变化,视图的操作也可以直接操作数据。
4.一个简单的示例
既然已经了解了其原理,接下来我们来写一个h5页面,代码如下:
<body>
<script src="../js/vue.js"></script>
<!-- 1.创建一个需要被操作的视图盒子 -->
<div id="box1">
<!-- 6.引用字符串message -->
<p>{{message}}</p>
<!-- 7.v-model指定输入框引用字符串message -->
<input v-model="message">
</div>
<script>
/*2.创建一个ViewModel实例*/
var vm=new Vue({
/*3.关联视图区*/
el:"#box1",
/*4.关联数据区 数据区内可以指定多个数据*/
data:{
/*5.声明了一个字符串message*/
message:"hello world !"
}
});
</script>
</body>
5.vue的指令学习
下面介绍了一些简单的指令集,如果还想学习更多,可以查看官网Api.
v-text指令
还记得上面代码引用一个字符串吗?
<p>{{message}}</p>
我们可以通过v-text指令这么写:
<p v-text='message'/>
v-once指令
<!-- 6.引用字符串message -->
<p>{{message}}</p>
<!-- 7.v-model指定输入框引用字符串message -->
<input v-model="message">
在上面的例子中,因为p标签和input标签都引用了同一个字符串message,只要输入框的文本改变了,那么p标签对应的数据也会跟着改变。而如果添加了v-once指令,那么p标签只会显示第一次赋值时的字符串:
<p v-once>{{message}}</p>
<input v-model="message" />
v-if指令
v-if指令表示一个条件,也就是js的布尔值可以决定实现某些操作,比如下面我们可以根据js的boolean值决定显示用户的身份:
<body>
<div id="box1">
<p v-if="isVip">Vip尊贵会员</p>
<p v-if="!isVip">普通会员</p>
</div>
<script>
var vm=new Vue({
el:"#box1",
data:{
isVip:true
}
})
</script>
</body>
v-show指令
v-show指令的操作与v-if指令相似,都可以根据boolean值决定是否显示某个标签,上面的代码经过改造之后效果一样,代码如下:
<div id="box1">
<p v-show="isVip">Vip尊贵会员</p>
<p v-show="!isVip">普通会员</p>
</div>
那么他们的区别在哪里啊?
使用了v-if指令的渲染效果是这样的,也就是他是根据条件来决定显示哪个标签的,只显示一个:
使用了v-show指令,通过源码可以看出他实际上将多个标签渲染出来了,再根据css来决定是否隐藏:
v-else-if 和 v-else指令
<div id="box1">
<p v-if="userLevel==0">普通用户</p>
<p v-else-if="userLevel==1">铜牌会员</p>
<p v-else-if="userLevel==2">银牌会员</p>
<p v-else>金牌会员</p>
</div>
<script>
var vm=new Vue({
el:"#box1",
data:{
/*
* 0:普通用户
* 1:铜牌会员
* 2:银牌会员
* 3:金牌会员
* */
userLevel:1
}
})
</script>
v-for指令
与java里面的增强性for循环类型,下面的引用中 创建了socre变量,那么后面的标签就可以使用了:
<div id="box1">
<p v-for="socre in scores">身高:{{socre}}</p>
</div>
<script>
var vm=new Vue({
el:"#box1",
data:{
scores:[
99,85,40,66,78
]
}
})
</script>
下面贴出效果图:
我们甚至可以通过后台返回的一系列数据,将其组装成一个表,代码如下:
<head>
<meta charset="UTF-8">
<title>07_Vue常见指令v-for</title>
<script src="../js/vue.js"></script>
<style type="text/css">
*{
margin:0px;
padding:0px;
}
table{
width:600px;
border:solid 2px pink;
text-align: center;
}
thead{
font-weight:bold;
background-color: red;
}
</style>
</head>
<body>
<div id="box1">
<table >
<thead>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>身高</td>
</tr>
</thead>
<tbody>
<tr v-for="person in persons">
<td>{{person.name}}</td>
<td>{{person.age}}</td>
<td>{{person.height}}</td>
</tr>
</tbody>
</table>
</div>
<script>
var vm=new Vue({
el:"#box1",
data:{
persons:[
{name:"张三",age:20,height:17.5},
{name:"李四",age:22,height:18},
{name:"王五",age:24,height:1.63},
]
}
})
</script>
</body>
v-bind指令
上面的过程中,我们将的是将简单的文本数据进行赋值,对于除了文本数据的其他属性的操作是不成功的,比如下面的代码将图片的地址写在vue里面,进行赋值是不成功的:
<div class="box1">
<img src="imgSrc" alt="tupian" />
</div>
<script>
var vm=new Vue({
el:".box1",
data:{
imgSrc:"../img/logo.png",
}
})
</script>
解决方案A:
<img v-bind:src="imgSrc" alt="tupian" />
这样设置后就可以直接显示了。如果你发现v-bind在编辑器中报红,你可以下载一个叫vue的插件。
解决方案B:
<img :src="imgSrc" alt="tupian" />
上面的代码v-bind是可以忽略的,如上这么写默认就是v-bind。
v-on指令
v-on指令是针对点击事件的一个指令,与v-bind指令一样,有2种写法(注释/非注释的):
<div class="box1">
<!--
<p v-text="tip"
v-on:click="clickImg('提示被点击了!')" />
-->
<p v-text="tip"
@click="clickImg('提示被点击了!')" />
</div>
<script>
var vm=new Vue({
el:".box1",
data:{
imgSrc:"../img/logo.png",
tip:"提示",
},
methods:{
clickImg(str){
alert(str);
}
}
})
</script>
6.组件化
组件化可以将我们的界面组件进行重复利用,Vue的另一大优势就是组件化,其使用的方式又分为2种:全局组件&局部组件,全局组件是整个页面都能使用的组件,局部组件会关联每一个ViewModel实例。下面分别介绍这2种创建方式。
打开JD界面,可以看到如下图,这里的界面模块差不多,我们可以创建统一的模板来进行处理。
1.全局组件化
全局组件化分为3个步骤:创建构造器,注册组件,使用组件,如下代码:
<body>
<div id="box1">
<!-- 3.使用组件 -->
<st></st>
</div>
<script>
//1.创建构造器
var Profile=Vue.extend({
template:'<h1>这是一个简单的标题!</h1>'
});
//2.注册组件
Vue.component("st",Profile);
new Vue({
el:"#box1"
})
</script>
</body>
你也可以简化如下写法:
<body>
<div class="box1">
<!-- 3.使用组件 -->
<st></st>
</div>
<script>
//1.创建构造器
//2.注册组件
Vue.component("st",{
template:'<h1>Hello Simple Title</h1>'
})
new Vue({
el:'.box1'
})
</script>
</body>
2.局部组件化
局部变量绑定到的是某一个ViewModel实例中,代码如下:
<body>
<div id="box">
<haha></haha>
</div>
<script>
var Profile=Vue.extend({
template:"<h1>这是一个简单的局部标题</h1>"
});
new Vue({
el:"#box",
components:{
"haha":Profile
}
})
</script>
</body>
简化写法如下:
<body>
<div id="box">
<haha></haha>
</div>
<script>
new Vue({
el:"#box",
components:{
"haha":{
template:"<h1>简单创建的方式</h1>"
}
}
})
</script>
</body>
3.子组件化
一个组件可以由很多的子组件组合而成,相信学习过移动开发端的同学都比较清晰,下面介绍如何使用子组件:
<body>
<div id="box1">
<haha></haha>
</div>
<script>
var childProfile=Vue.extend({
template:'<img src="../img/logo.png"/>'
});
var parentProfile=Vue.extend({
components:{
"childT":childProfile
},
template:'<div><childT></childT><p>模糊的照片</p></div>'
})
Vue.component("haha",parentProfile);
new Vue({
el:"#box1"
})
</script>
</body>
4.采用template和script标签进行模板化
前面我们创建的组件中都有一套统一的模板代码,但模板代码的可读性很差,如下介绍模板新的写法:
<div id="box">
<my-component></my-component>
<script-component></script-component>
</div>
<template id="component_id">
<h1>这是一个简单的template标题</h1>
</template>
<script type="text/template" id="script_id">
<h1>这是一个简单的script标题</h1>
</script>
<script>
//注册一个组件
Vue.component("my-component",{
template:'#component_id'
});
//注册一个组件
Vue.component("script-component",{
template:'#script_id'
});
new Vue({
el:'#box'
});
</script>
5.获取组件内部数据
如果我们想获取Vue内部实例的数据,我们可以在Vue内部的data代码块中声明,但在组件构造器中,如果想对外提供数据,使用的不是代码块而是函数,我们可以将需要返回的数据以JSON的方式将需要提供的数据进行返回。
如下我们的组件对外提供了一个叫做message的数据,如下:
<div id="box">
<my-component></my-component>
</div>
<template id="cp_template">
<h1>{{message}}</h1>
</template>
<script>
var Profile=Vue.extend({
template:'#cp_template',
//组件中提供的数据需要通过函数返回
data(){
return {
message:'这是函数里面的数据'
}
}
});
Vue.component("my-component",Profile);
new Vue({
el:"#box"
});
</script>
6.组件对外提供了属性配置
为了让我们创建的组件更加通用,我们可以通过属性的方式对客户端提供相关的配置,如下我们让客户端设置对应的argument属性值,并在该组件中打印该值的内容:
<div id="box">
<my-component argument="hello参数"></my-component>
</div>
<template id="cp_tmp" >
<h1>这是组件模板中的一个简单的标题 {{argument}}</h1>
</template>
<script>
Vue.component("my-component",{
props:["argument"],
template:'#cp_tmp'
});
new Vue({
el:'#box'
});
</script>
props可以指定声明一个或者多个属性名称,当然组件也存在相互嵌套的时候,以下介绍嵌套的组件是如何对外提供属性的,注意,对于不是文本的属性,需要动态绑定使用。
<div id="box">
<parent-component :imgsrc="imgSrc" title="title"></parent-component>
</div>
<template id="child_id">
<img :src="imgsrc" />
</template>
<template id="parent_id">
<div>
<my-child :imgsrc="imgsrc"></my-child>
<br>
<h1>{{title}}</h1>
</div>
</template>
<script>
var child =Vue.extend({
props:["imgsrc"],
template:'#child_id'
});
var parent =Vue.extend({
props:["imgsrc","title"],
template:'#parent_id',
components:{
"my-child":child
}
});
Vue.component("parent-component",parent);
new Vue({
el:"#box",
data:{
imgSrc:"../img/logo.png",
title:"这是一个标题"
}
});
</script>
7.组件嵌套下的点击事件
上面的属性开发中我们发现 属性是由父组件层层往里面传递的,而点击事件则是由子组件传递给父组件的。这里我们通过v-on指令和vue.$emit()来实现。
下面我们通过一个子组件点击事件来控制父组件内部的数据,效果图如下:
代码如下:
<div id="box">
<parent></parent>
</div>
<template id="child_id">
<button @click="countData">{{counter}}</button>
</template>
<template id="parent_id">
<div>
<p>{{totalCounter}}</p>
<child @countevent="calculate()"></child>
<child @countevent="calculate()"></child>
<child @countevent="calculate()"></child>
</div>
</template>
<script>
Vue.component("child",{
data(){
return {
counter:0
}
},
template:"#child_id",
methods:{
countData(){
this.counter+=1;
//触发某个事件
this.$emit('countevent');
}
}
});
Vue.component("parent",{
data(){
return {
totalCounter:0
}
},
template:"#parent_id",
methods:{
calculate(){
this.totalCounter+=1;
}
}
});
new Vue({
el:"#box"
});
</script>
7.样式的使用
样式的操作有2种,一种是操作style标签,一种的操作class标签。使用如下:
style标签
<body>
<div id="box1">
<p :style="pstyle">Style样式</p>
</div>
<script>
new Vue({
el:"#box1",
data:{
pstyle:{
backgroundColor: 'red',
textAlign: 'center',
fontSize: '22px'
}
}
})
</script>
</body>
class标签
<head>
<meta charset="UTF-8">
<title>15_子组件的应用</title>
<script src="../js/vue.js"></script>
<style>
.normal{
background-color: red;
}
.active{
background-color: blue;
}
</style>
</head>
<body>
<div id="box1">
<p :class="isActive?'active':'normal'">class样式</p>
<button @click="changeColor">改变颜色</button>
</div>
<script>
new Vue({
el:"#box1",
data:{
isActive:true
},
methods:{
changeColor(){
this.isActive=!this.isActive;
}
}
})
</script>
</body>
8.插槽
在一个组件模板中,我们希望有些布局应该由客户端来实现,此时我们可以使用Vue提供给我们的插槽来实现。
插槽:就像我们电脑主板一样,整个框架的固定的,但是我们可以根据需要插入不同型号的子组件。
插槽分为2种,匿名插槽和实名插槽。
匿名插槽
比如我想实现一个小界面,该界面的由上中下三部分组件,而中间的部分是可以替换的,此时我们的代码如下:
<div id="box1">
<my-component>
<!--客户端决定中间部分的内容 注意这里应该只有一个根标签-->
<div>
<img src="../img/logo.png" alt="">
</div>
</my-component>
</div>
<br>
<div id="box2">
<my-component>
<h1>Box2的内容</h1>
</my-component>
</div>
<template id="my_component">
<!--定义模板-->
<div id="container">
<h1 id="header">这是一个头部</h1>
<slot>中间这部分由使用该组件的客户端决定显示需要的内容</slot>
<h1 id="footer">这是一个底部</h1>
</div>
</template>
<script>
Vue.component("my-component",{
template:"#my_component"
});
new Vue({
el:"#box1"
});
new Vue({
el:"#box2"
});
</script>
实名插槽
匿名插槽比较符合一个模板中只需要一个插槽的需求。而如果一个模板需要多个插槽,就需要为每一个插槽设置名称,代码如下:
<div id="box">
<my-component>
<div slot="cpu">inter core i7</div>
<div slot="gpu">xxx gpu</div>
<div slot="memory">xxx 内存条</div>
<div slot="storage">xxx 硬盘</div>
</my-component>
</div>
<template id="component">
<div id="container">
<slot name="cpu">这是插入CPU</slot>
<slot name="gpu">这是插入GPU</slot>
<slot name="memory">这是插入MOMORY</slot>
<slot name="storage">这是插入STORAGE</slot>
</div>
</template>
<script>
Vue.component("my-component",{
template:'#component'
});
new Vue({
el:"#box"
});
</script>