目录
一、准备工作:
首先:我们先引入vue.js,我这里用的是:2.0版本的vue.js
如果不会使用的大家可以参考Vue的官方文档:Vue.js - 渐进式 JavaScript 框架 | Vue.js
<!-- 引入vue核心js -->
<script src="js/vue.js" type="text/javascript"></script>
二、Vue的样式绑定
1.样式绑定:
1.1 class绑定(已经在<style></style>中定义的样式)
使用方式:v-bind:class="expression"
expression的类型:字符串、数组、对象
1.2 style绑定(属性style定义样式)
v-bind:style="expression"
expression的类型:字符串、数组、对象
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 引入vue核心js -->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<style>
.cl{
color: red;
font-weight:bold;
}
.cl1{
font-size: 35px;
}
</style>
<body>
<!-- Vue的基本使用 -->
<div id="app">
<h1>{{msg}}</h1>
<!-- @click:v-on:click点击事件的简写形式 -->
<button @click="test">有种点我</button><br/>
<!-- 普通形式:class形式:-->
<span class="cl">牛逼轰轰</span>
<!-- 普通形式:style形式:-->
<span style="color:blue;font-weight:600;">牛逼轰轰</span>
<h1>Vue方式的style和class:1.字符串、2.数组、3.对象</h1>
<h2>1.字符串形式:</h2>
<div v-bind:style="{color:color,fontSize:size+'px'}">
飞雪连天射白鹿
</div>
<!-- v-bind:的省略形式 : -->
<h2>2.数组形式(class绑定):</h2>
<div :class="cls">
笑书神侠倚碧鸳
</div>
<h2>3.对象形式(style绑定)</h2>
<div :style="styleObj">
青山横北郭,白水绕东城
</div>
<!-- 基于Vue框架,定义的script模型规则 -->
<script>
var flag = false;
//实例化:Vue
var vue = new Vue({
el:"#app",//定义边界:也就是Vue的作用范围
data:function(){//此处定义vue的变量
return {
"msg":"张三",
"color":'pink',
"size":'50',
"cls":['cl','cl1'],//以数组的形式套样式
"styleObj":{//以对象形式套样式
color:'green',
fontSize:"26px",
fontWeight:'blod'
}
}
},
//定义方法:
methods:{
test:function(){
console.log(123);
if(!flag){
this.msg="老六";
flag=true;
}else{
this.msg="张三";
flag=false;
}
}
}
});
</script>
</body>
</html>
运行效果:
三、Vue的修饰符
事件处理器: 事件监听可以使用v-on 指令
1. 事件修饰符
Vue通过由点(.)表示的指令后缀来调用修饰符
.stop
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
.stop阻止冒泡事件案例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>作用:阻止事件冒泡</title>
<!-- 引入核心vue.js -->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<body>
<!-- (2)事件冒泡处理可能会激活我们本来不想激活的事件,导致程序错乱,
甚至无从下手调试,这常成为对事件冒泡不熟悉程序员的棘手问题。所以必要时,我们要阻止事件冒泡。 -->
<!-- -->
<h1>阻止事件冒泡</h1>
<div @click="showMsg()" id="outSide" style="width:100px; height:100px; background:#000; padding:50px">
<!-- 我们在子标签的事件中,使用vue的事件修饰符 .stop,阻止了冒泡事件的发生 -->
<!-- 什么是冒泡事件:冒泡事件就是子标签和父标签都设置了相同事件,一旦子标签的事件被触发,那么父标签的事件也将被触发(由里到外扩散) -->
<!-- /* 简单来讲:事件被触发时父元素的事件就会被触发 */ -->
<!-- 当我们把.stop去掉之后,运行,在单击id="inSide"的div盒子,就会发现它的父标签的click事件也被触发了 -->
<div @click.stop="Msg()" id="inSide" style="width:100px; height:100px; background:#CCC"></div>
</div>
<script type="text/javascript">
//阻止事件冒泡后,你点击灰色盒子,整个过程只弹一次对话框了(注意与默认情况对比)
var vue = new Vue({
//el:定义作用域
el:'#outSide',
//data:专门定义v-bind/v-model/{{}}...中的属性
data:function(){
return{
}
},
methods:{
showMsg:function(){
console.log("showMsg");
},
Msg:function(){
console.log("Msg");
}
}
});
</script>
</body>
</html>
效果演示:
什么是事件冒泡?(官方解释)
答:
在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。
打个比方说:你在地方法院要上诉一件案子,如果地方没有处理此类案件的法院,地方相关部门会帮你继续往上级法院上诉,比如从市级到省级,直至到中央法院,最终使你的案件得以处理。
.prevent(一般作用于验证)
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
.capture
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
.self
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
.once
<!-- click 事件只能点击一次 -->
<a v-on:click.once="doThis"></a>
部分案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 引入vue核心js -->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<body>
<!-- Vue的基本使用 -->
<div id="app">
<h1>{{msg}}</h1>
<!-- @click:事件的简写形式 -->
<!-- 示例一:stop阻止单击事件冒泡(由于没有做相应的处理,所以效果展示不出)-->
<h2>示例一:</h2>
<!-- <button @click.stop="dothis()">有种点我</button><br/> -->
<!-- 示例二:once点击一次 :只打印了结果一次,再次单击没有触发对应事件打印的效果-->
<h2>示例二:</h2>
<button @click.once="dothis()">有种点我</button><br/>
<!-- 示例三: -->
<h2>示例三:</h2>
<form action="userLogin.action" @submit.prevent="doSumbit">
账号:<input type="text" v-model="msg" />
<input type="submit" value="提交"/>
</form>
</div>
<script>
var flag = false;
//实例化:Vue
var vue = new Vue({
el:"#app",//定义边界:也就是Vue的作用范围
data:function(){//此处定义vue的变量
return {
"msg":"张三",
}
},
//定义方法:
methods:{
dothis:function(){
console.log(123);
if(!flag){
this.msg="老六";
flag=true;
}else{
this.msg="张三";
flag=false;
}
},
doSumbit:function(){
console.log("doSumbit");
}
}
});
</script>
</body>
</html>
运行效果:
2.按键修饰符
Vue允许为v-on在监听键盘事件时添加按键修饰符:
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">
Vue为最常用的按键提供了别名
<!-- 同上 -->
<input v-on:keyup.enter="submit">
全部的按键别名:
- .enter
- .tab
- .delete (捕获 "删除" 和 "退格" 键)
- .esc
- .space
- .up
- .down
- .left
- .right
- .ctrl
- .alt
- .shift
- .meta
案例演示(其它按键效果的与此相同):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 引入vue核心js -->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<body>
<!-- Vue的基本使用 -->
<div id="app">
<!-- "doKeyDown()"中的"()"可以省略 -->
<!-- @keydown.enter:键盘按下事件,必须按下enter回车键才能触发方法"doKeyDown" -->
<input type="text" @keydown.enter="doKeyDown()" />
</div>
<script>
var flag = false;
//实例化:Vue
var vue = new Vue({
el:"#app",//定义边界:也就是Vue的作用范围
data:function(){//此处定义vue的变量
return {
//"msg":"张三",
}
},
//定义方法:
methods:{
doKeyDown:function(){
console.log("doKeyDown");
}
}
});
</script>
</body>
</html>
运行结果:
四、 Vue表单标签&修饰符(基于注册案例)
修饰符
.lazy
默认情况下, v-model在input事件中同步输入框的值与数据,但你可以添加一个修饰符lazy,从而转变为在change事件中同步
.number 使用方式如下(以下修饰符使用方式与此一致):
账号:<input type="text" v-model.number="username" /><br/>
将用户的输入值转为 Number 类型
.trim
自动过滤用户输入的首尾空格
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 引入vue核心js -->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<body>
<!-- Vue的基本使用 -->
<div id="app">
<!-- .number:由于input默认提交的都是String类型的数据,加上了.number,数据在满足数字的格式的时候就会自动转换为数字格式 -->
账号:<input type="text" v-model.number="username" /><br/>
密码:<input type="password" v-model="password" /><br/>
性别:<input type="radio" v-model="sex" value="1" />男
<input type="radio" v-model="sex" value="2" />女<br/>
籍贯:<select v-model="areaSelected">
<option value=''>---请选择---</option>
<option v-for="a in area" :value="a.id">
{{a.name}}
</option>
</select><br/>
<!-- div和span标签之间的区别
div:占满整个一行
span:行内显示
-->
爱好:
<span v-for="h in hobbies">
<!-- :value="h.id":少了,每一个复选框都成了"全选" -->
<input type="checkbox" v-model="hobby" :value="h.id"/>
{{h.name}}
</span><br/>
备注:<textarea v-model="remark"></textarea><br/>
<div><input type="checkbox" v-model="flag" />阅读以上内容</div>
<!-- :disabled:启用和禁用 -->
<button @click="doRegister" :disabled="!flag">注册</button>
<script>
var flag = false;
//实例化:Vue
var vue = new Vue({
el:"#app",//定义边界:也就是Vue的作用范围
data:function(){//此处定义vue的变量
return {
username:'',
password:'',
sex:'1',
area:[
{id:1,name:'长沙'},
{id:2,name:'株洲'},
{id:3,name:'湘潭'},
{id:4,name:'衡阳'}
],
areaSelected:'',
hobbies:[
{id:1,name:'听音乐'},
{id:2,name:'羽毛球'},
{id:3,name:'下棋'}
],
hobby:[],
remark:'',
flag:false
}
},
//定义方法:
methods:{
doRegister:function(){
let params={
username:this.username,
password:this.password,
sex:this.sex,
area:this.areaSelected,
hobby:this.hobby,
remark:this.remark
};
console.log(params);
}
}
});
</script>
</body>
</html>
效果展示:
六、自定义指令
除了Vue自带的指令(v-on|v-model)等, Vue也允许注册自定义指令,根据作用范围又分为:
全局指令/局部指令
Vue.directive("focus",{});//全局指令
new Vue({
el:"#d1",
directives:{//局部指令
focus:{}
}
});
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 引入vue核心js -->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<body>
<!-- Vue的基本使用 -->
<div id="app">
<h2>局部指令</h2>
<div v-fos="name">
</div>
<h2>全局指令</h2>
<div v-kfc="22"></div>
</div>
<script>
var flag = false;
/* 全局指令 :作用域更大,都可以调用到*/
Vue.directive('kfc',{
inserted:function(el,binding){
console.log(el);
console.log(binding);
}
})
//实例化:Vue
var vue = new Vue({
el:"#app",//定义边界:也就是Vue的作用范围
data:function(){//此处定义vue的变量
return {
name:'zs'
}
},
//定义方法:
methods:{
},
//自定义指令:仅在实例Vue里被调用
directives:{
fos:{
inserted:function(el,binding){//钩子函数
//el:打印当前所在的元素
console.log(el);
//打印的基本信息
console.log(binding);
}
}
}
});
</script>
</body>
</html>
效果展示:
指令须知:
指令定义函数提供了几个钩子函数用来帮助实现功能(可选)
bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作
inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
unbind: 只调用一次, 指令与元素解绑时调用。钩子函数的参数有:
el: 指令所绑定的元素,可以用来直接操作 DOM 。
binding: 一个对象,包含以下属性:
name: 指令名,不包括 v- 前缀。
value: 指令的绑定值, 例如: v-my-directive="1 + 1", value 的值是 2。
oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression: 绑定值的表达式或变量名。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"。
arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 "foo"。
modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
vnode: Vue 编译生成的虚拟节点。
oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
七、组件
组件的作用:一个独立页面(组件),封装重用代码的目的,一个完整的页面由n多个组件组成。
1 组件简介
组件(Component)是Vue最强大的功能之一
组件可以扩展HTML元素,封装可重用的代码
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
2 全局和局部组件
全局组件:Vue.component(tagName, options),tagName为组件名,options为配置选项。
局部组件: new Vue({el:'#d1',components:{...}})
注册后,我们可以使用以下方式来调用组件:
<tagName></tagName>
3 props
props是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过props把数据传给子组件,子组件需要显式地用props选项声明 "prop"
注1:因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods
以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。
4.注意事项:
注2:当我们定义这个 <button-counter> 组件时,你可能会发现它的data并不是像这样直接提供一个对象
data: {
count: 0
}取而代之的是,一个组件的data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () {
return {
count: 0
}
}
注3:定义组件名的方式有两种
短横线分隔命名(建议使用)
Vue.component('my-component-name', { /* ... */ }),引用方式:<my-component-name>首字母大写命名
Vue.component('MyComponentName', { /* ... */ }),引用方式: <my-component-name>和<MyComponentName>都是可接受的注4:HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,
camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
props: ['postTitle'],<my-tag post-title="hello!"></my-tag>注5:props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
希望每个 prop 都有指定的值类型
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 引入vue核心js -->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<body>
<!-- Vue的基本使用 -->
<!-- 不管是全局组件还是局部组件都是作用在id为app的div标签范围内,而app归属于new Vue,而且两者的运行不会相互影响 -->
<div id="app">
<h2>局部组件&全局组件</h2>
<!-- 自定义局部组件 -->
<!-- @three-click:在99行中定义 -->
<!-- 相当于在组件内部模拟了一个事件,在自定义有组件中定义这个事件,调用父组件,将你定义的那个组件的值传递过去 -->
<!-- 注:doTest不能加括号,因为有参数 -->
<kfc-button @three-click="doTest"></kfc-button>
<!-- :firstName:允许传入动态或静态Prop类型 -->
<ff-button :firstName="name"></ff-button>
</div>
<script>
var flag = false;
/* 全局组件 :作用域更大,都可以调用到*/
Vue.component('ff-button',{
//有且只有一个根节点
//有可能template是一个表格
template:"<div><h1>[全局组件]</h1><button @click='doClick'>被点击了{{count}}次</button></div>",
props:['firstName'],
//在自定义组件中请使用函数方法
data:function(){
return{
count:0
}
},
methods:{
doClick:function(){
console.log("全局组件:从父到子传过来的属性值:"+this.firstName);
this.count++;
}
}
});
//实例化:Vue
//组件的定义:
//1)全局组件:Vue.component(组件名称,配置选项)
//2)局部组件:new Vue({...,components{...}})
//全局组件和局部组件的父组件都是new Vue();Vue实例
//组件的命名:
//1)短横线命名法:kfc-button
//2)首字符大写命名法(帕斯卡):KfcButton
//什么是驼峰命名法:kfcButton
//组件之间的传参
//1)父到子:采用props属性方式传递参数,允许传递基本类型、对象及动态值(类似:一瓶水,我们需要往里面注入一些东西,我们就需要打开盖子(开个孔(入口)))
//2)子到父:采用事件方式传递参数,$emit
var vue = new Vue({
el:"#app",//定义边界:也就是Vue的作用范围
data:function(){//此处定义vue的变量
return {
name:'zs'
}
},
//定义方法:
methods:{
doTest:function(c){
console.log("从子到父传过来的属性值:"+c);
}
},
//局部组件
components:{
'kfc-button':{
//有且只有一个根节点
//有可能template是一个表格
/* template:"<div><h1>[局部组件]</h1><button @click='doClick'>被点击了{{count}}次</button></div>", */
/* 子传父形式 */
template:"<div><h1>[局部组件]</h1><button @click='doThreeClick'>被点击了{{count}}次</button></div>",
props:['firstName'],
//在自定义组件中请使用函数方法
data:function(){
return{
count:0
}
},
methods:{
doClick:function(){
this.count++;
},
//子到父测试
doThreeClick:function(){
this.count++;
if(this.count%3==0){
console.log("局部组件:从父到子传过来的属性值:"+this.firstName);
console.log("[局部组件]count=%s",this.count);
//将事件传过去
this.$emit('three-click',this.count);
}
}
}
}
}
});
</script>
</body>
</html>
效果展示:
组件文件:.vue 后缀结尾
形式例如:
<template><!-- 相当于子页面:存放html代码 -->
</template>
<script>
/* 自定义组件js代码存放
作用范围:仅在当前Vue实例(当前组件内有效)
例如:
data:function(){
return{
count:0
}
},
methods:{
doClick:function(){
this.count++;
}
}
*/
</script>
<style>
/* 组件样式 */
</style>
组件传值作用:用于主页面左侧菜单折叠的参数传递
八、自定义事件
监听事件:$on(eventName)
触发事件:$emit(eventName)注1:Vue自定义事件是为组件间通信设计
vue中父组件通过prop传递数据给子组件,而想要将子组件的数据传递给父组件,则可以通过自定义事件的绑定
父Vue实例->Vue实例,通过prop传递数据
子Vue实例->父Vue实例,通过事件传递数据注2:事件名
不同于组件和prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称
建议使用“短横线分隔命名”,例如:three-click
# 只配合一个事件名使用 $emit:
<div id="emit-example-simple">
<!-- 父組件中子組件的引用处添加函数v-on:function="function1"
其中function为子组件中使用函数,function1为父组件赋值函数 -->
<welcome-button v-on:welcome="sayHi"></welcome-button>
</div>
<script>
Vue.component('welcome-button', {
template: `
<button v-on:click="$emit('welcome')">
Click me to be welcomed
</button>
`
})
new Vue({
el: '#emit-example-simple',
methods: {
sayHi: function () {
alert('Hi!')
}
}
})
</script>
# 配合额外的参数使用 $emit:
<div id="app">
<div id="counter-event-example">
<!-- 父組件中子組件的引用處添加函数v-on:function="function1"
其中function为子组件中使用函数,function1为父组件赋值函数 -->
<magic-eight-ball v-on:give-advice="showAdvice"></welcome-button>
</div>
</div>
<script>
Vue.component("magic-eight-ball", {
data:function(){
return{
possibleAdvice:["Yes","No","Maybe"]
}
},
methods:{
giveAdvice:function(){
var randomAdviceIndex=Math.floor(Math.random()*this.possibleAdvice.length)
this.$emit('give-advice',this.possibleAdvice[randomAdviceIndex])
}
},
template: `
<button v-on:click="giveAdvice">
Click me to for advice
</button>
`
});
new Vue({
el: '#counter-event-example',
methods: {
showAdvice: function (advice) {
alert(advice)
}
}
})
</script>
数据传递
<div id="app">
<parent></parent>
</div>
<script>
//定义局部子组件
var childNode={
template:`
<div class="child">
<div>
<span>子组件数据</span>
<input v-model="childMsg" v-on:input="data">
</div>
<p>{{childMsg}}</p>
</div>
`,
data(){
return {
childMsg:"我不猜"
}
},
methods:{
data(){
this.$emit('pass-data',this.childMsg)
}
}
}
//定义父组件
var parentNode={
template:`
<div class="parent">
<div>
<span>父组件数据</span>
<input v-model="msg">
</div>
<p>{{msg}}</p>
<child v-on:pass-data="getData"></child>
</div>
`,
components:{
'child':childNode
},
data(){
return {
msg:"你猜"
}
},
methods:{
getData(value){
this.msg=value;
}
}
}
new Vue({
el: '#app',
components:{
'parent':parentNode
}
})
</script>
效果演示:
子组件通过数据绑定将自身的信息传递给父组件,从而改变父组件内容。
注:
现在在组件上使用 v-on 只会监听自定义事件 (组件用 $emit 触发的事件)。如果要监听根元素的原生事件,可以使用 .native 修饰符,比如:
<my-component v-on:click.native="doSomething"></my-component>