一、Vue实例配置选项
选项 | 说明 |
---|---|
data | Vue实例数据对象 |
methods | 定义Vue中的方法 |
components | 定义子组件 |
computed | 计算属性 |
filters | 过滤器 |
el | 唯一根标签 |
watch | 监听数据变化 |
1.el唯一根标签
在创建Vue实例时,el表示唯一根标签,class或id选择器可以用来将页面结构与Vue实例对象中的el绑定。
<div id="app">{{name}}</div>
<script>
var vm=new Vue({
el:"#app",
data:{
name:"Vue实例创建成功!"
}
})
</script>
2.data初始数据
Vue实例的数据对象为data,Vue会将data的属性转换为getter,setter,从而让data的属性都能够响应数据变化。
Vue实例创建后,可以通过**vm. d a t a ∗ ∗ 访 问 原 始 数 据 对 象 。 V u e 实 例 也 代 理 了 d a t a 对 象 上 所 有 的 属 性 , 因 此 访 问 v m . n a m e 相 当 于 访 问 v m . data**访问原始数据对象。Vue实例也代理了data对象上所有的属性,因此访问vm.name相当于访问vm. data∗∗访问原始数据对象。Vue实例也代理了data对象上所有的属性,因此访问vm.name相当于访问vm.data.name。
2.1 data赋值方式一
<div id="app">
<p>
{{name}}
</p>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
name:'定义初始数据'
}
})
console.log(vm.$data.name);
console.log(vm.name);
</script>
2.2 data赋值方式二
<div id="vue_data">
<h3>{{site}}</h3>
<h3>{{url}}</h3>
<h3>{{student}}</h3>
</div>
<script>
// 字典
var data = {
site: "菜鸟教程",
url: "https://www.baidu.com",
student: "Tom"
};
var vm = new Vue({
el: "#vue_data",
data: data
});
var h3 = document.querySelector('h3');
h3.addEventListener('click', function () {
data.site = '百度';
});
console.log(vm.site === data.site);
console.log(vm.$data.site === data.site);
console.log(vm.$data === data);
</script>
3.methods定义方法
methods属性用来定义方法,通过Vue实例可以访问这些方法。在定义的方法中,this指向Vue实例本身。定义在methods属性中的方法可以作为页面中的事件处理方法使用,当事件被触发后,执行相应的事件处理方法。
<div id="app">
<button @click="showInfo">
请单击
</button>
<p>
{{msg}}
</p>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
msg:''
},
mehods:{
//定义时间处理方法showInfo
showInfo(){
this.msg='触发单击事件'
}
}
})
</script>
4.computed计算属性
Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动,当有一些数据需要随着其他数据而变动时,就需要使用computed计算属性。
在事件处理方法中,this指向的Vue实例的计算属性结果会被缓存起来,只有依赖的响应式属性变化时,才会重新计算,返回最终结果。
4.1 案例:增加数量计算总价
<div id="app">
<p> 总价格:{{totalPrice}}</p>
<p> 单价:{{price}}</p>
<p> 数量:{{num}}</p>
<div>
<button @click="num == 0?0:num--">减少数量</button>
<button @click="num++">增加数量</button>
</div>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
price: 20,
num: 0
},
methods: {//整个页面重新渲染的时候才会执行
sum: function () {
return this.price * this.num;
}
},
computed: {//依赖的缓存被更改的时候就会执行,在有依赖的情况下执行效率要高一点
//总价格计算
totalPrice: function () {
return this.price * this.num;
}
}
});
</script>
5.watch状态监听
Vue提供了watch状态监听功能,只需监听当前Vue实例中的数据变化,就会调用数据所绑定的事件处理方法。
5.1 基础使用
<div id="app">
<input type="text" v-model="cityName">
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
cityName:'shanghai'
},
// 使用watch监听cityName变化
watch:{
cityName(newName,oldName){
// 打印新数据和旧数据
console.log(newName,oldName);
}
}
})
</script>
5.2 计算总价
<div id="app">
<p> 总价格:{{sum}}</p>
<p> 单价:{{price}}</p>
数量:<input type="number" v-model="num"/>
<div>
<button @click="num == 0?0:num--">减少数量</button>
<button @click="num++">增加数量</button>
</div>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
sum: 0,
price: 20,
num: 0
},
watch: {
num(newData, oldData) {
if (newData < 0) {
this.num = 0;
}
this.sum = newData * this.price;
}
}
});
</script>
5.3 距离转换km<=>m
<h2>距离转换</h2>
<div id="km_m">
<input type="number" v-model="km"/>千米<br/>
<input type="number" v-model="m"/>米<br/>
</div>
<div id="info"></div>
<script>
var vm1 = new Vue({
el: "#km_m",
data: {
km: 0,
m: 0
},
watch: {
km: function (newData, oldData) {
this.m = newData * 1000;
},
m: function (newData, oldData) {
this.km = newData / 1000;
}
}
});
vm1.$watch('km', function (newValue, oldValue) {
var info = document.querySelector('#info');
info.innerHTML = '修改前的值是' + oldValue + ',修改后的值是' + newValue;
})
</script>
3-4-5.methods、computed、watch区别
<h2>三个属性的区别</h2>
<div id="name">
姓:<input type="text" v-model="firstName"/>
名:<input type="text" v-model="lastName"/>
<h4>用methods形式打印全名{{methodFullName()}},年龄{{age}}</h4>
<h4>用computed形式打印全名{{computedFullName}},年龄{{age}}</h4>
<h4>用watch形式打印全名{{watchFullName}},年龄{{age}}</h4>
</div>
<script>
var vm2 = new Vue({
el: '#name',
data: {
firstName: '张',
lastName: '三',
age: 18,
watchFullName: '张三'
},
methods: {
methodFullName: function () {
console.log("这是方法返回的全名");
return this.firstName + this.lastName;
}
},
computed: {
computedFullName: function () {
console.log("这是计算返回的全名");
return this.firstName + this.lastName;
}
},
watch: {
firstName: function (newValue) {
console.log('这是监听属性firstName的返回');
this.watchFullName = newValue + this.lastName;
},
lastName: function (newValue) {
console.log('这是监听属性lastName的返回');
this.watchFullName = this.firstName + newValue;
}
}
})
</script>
6.filters过滤器
数据变化除了在Vue逻辑层进行操作外,还可以通过过滤器来实现。
6.1在插值表达式中使用过滤器
通过"{{data}}“语法,可以将data中的数据插入页面中,该语法就是插值表达式,插值表达式中还可以使用过滤器来对数据进行处理,语法为”{{data | filter}}"
<div id="app">
{{message|toUpcase|toLowcase}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: "abcdefg"
},
filters: {
// 参数value表示传到过滤器中的数据
toUpcase: function (value) {
// 将abcdefg转换为ABCDEFG
return value ? value.toUpperCase() : '';
},
toLowcase: function (value) {
// 将ABCDEFG转换为abcdefg
return value ? value.toLowerCase() : '';
}
}
})
</script>
6.2在v-bind属性绑定中使用过滤器
v-bind用于属性绑定,如"v-bind:id=”data““表示绑定id属性,值为data。在data后面可以加过滤器,语法为"data|filter”。
<div id="app">
<div v-bind:id="dataId | formatId">
helloworld
</div>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
dataId:'dff1'
},
filters:{
//字符串处理
return value?vlaue.charAt(1)+value.indexOf('d'):'';
}
})
</script>
二、Vue数据绑定
1.绑定样式
1.1 绑定内联样式
在Vue实例中定义的初始数据data,可以通过v-bind将样式数据绑定给DOM元素。
<div id="app">
<!--绑定样式属性值-->
<div v-bind:style="{backgroundColor:pink,width:width,height:height}">
<div v-bind:style="myDiv"></div>
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
myDiv: {backgroundColor: 'red', width: '100px', height: '100px'},
pink: 'pink',
width: '100%',
height: '200px',
}
});
</script>
1.2绑定样式类
样式类即以类名定义元素的样式
<div id="app">
<div v-bind:class="{box}">
我是box
<div v-bind:class="{inner}">我是inner</div>
<div v-bind:class="{inner,text}">我是inner</div>
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
box: 'box',
inner: 'inner',
text: 'text'
}
});
</script>
1.3样式数组
<!--绑定的是数组-->
<div id="myArr">
<div v-bind:style="[baseStyle,myStyle]">今天是周四</div>
</div>
<script>
var myvm = new Vue({
el: '#myArr',
data: {
baseStyle: {
color: 'red',
fontSzie: '30px',
},
myStyle: {
'font-weight': 'bold'
}
}
})
</script>
1.4是否加载样式
<!--是否加载类样式-->
<div id="flag_css">
<div v-bind:class="{inner,active:isActive}"></div>
</div>
<script>
var flag_css = new Vue({
el: "#flag_css",
data: {
inner: 'inner',
isActive: true,
active: 'active'
}
})
</script>
1.5样式绑定综合
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>内联样式属性</title>
<script src="js/vue.js"></script>
<style>
.active {
width: 100px;
height: 100px;
background-color: blue;
}
.mytext {
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="{'active':isActive,'mytext':hasError}"></div>
<button @click="upIsActive">isActive</button>
<button @click="upHasError">hasError</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
isActive: true,
hasError: true
},
methods: {
upIsActive: function () {
this.isActive = !this.isActive;
},
upHasError: function () {
this.hasError = !this.hasError;
}
}
})
</script>
<!-- 对象表示形式 -->
<div id="app1">
<div v-bind:class="obj"></div>
<button @click="upIsActive">isActive</button>
<button @click="upHasError">hasError</button>
</div>
<script>
var vm1 = new Vue({
el: '#app1',
data: {
obj: {
active: true,
mytext: true
}
},
methods: {
upIsActive: function () {
this.obj.active = !this.obj.active;
},
upHasError: function () {
this.obj.mytext = !this.obj.mytext;
}
}
})
</script>
<!-- 计算属性绑定 -->
<div id="app2">
<div v-bind:class="comNum"></div>
<button @click="upIsActive">isActive</button>
</div>
<script>
var vm2 = new Vue({
el: '#app2',
data: {
isActive: true,
num: 100
},
methods: {
upIsActive: function () {
this.isActive = !this.isActive;
}
},
computed: {
comNum: function () {
return {
active: this.isActive && this.num >= 100,
hasError: this.isActive && this.num < 100
}
}
}
})
</script>
</body>
</html>
2.内置指令
指令 | 说明 |
---|---|
v-model | 双向数据绑定,页面修改同步 |
v-on | 监听事件,可简写为“@” |
v-bind | 单向数据绑定,页面修改不同步,可简写为“:” |
v-text | 插入文本内容 |
v-html | 插入包含HTML的内容 |
v-for | 列表渲染 |
v-if | 条件渲染 |
v-show | 显示隐藏 |
2.1 v-model 双向数据绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>内置指令</title>
<script src="js/vue.js"></script>
</head>
<body>
<!-- v-model双向数据绑定 -->
<div id="app">
<label>
姓名
<input type="text" v-model="name"/>
</label>
<label>
年龄
<input type="number" v-model="age"/>
</label>
<label>
性别
<input type="text" v-model="sex"/>
</label>
<hr/>
<p>姓名:{{name}}<br/>年龄:{{age}}<br/>性别:{{sex}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '张三',
age: 18,
sex: '男'
}
})
</script>
</script>
</body>
</html>
2.2 v-bind 单向数据绑定
数据仅可从model端到view端,详细请看绑定样式
2.3 v-text 文本填充
向DOM中添加文本内容
<!-- v-text插入文本内容 -->
<div id="app1">
<p v-text="msg"></p>
</div>
<script>
var vm = new Vue({
el: '#app1',
data: {
msg: '我是v-text'
}
})
</script>
2.4 v-html HTML标签填充
<!-- v-html HTML标签填充 -->
<div id="app2">
<div v-html="h"></div>
</div>
<script>
var vm = new Vue({
el: '#app2',
data: {
h: '<h1>我是v-html</h1>'
}
})
</script>
2.5 v-on 事件监听指令
<!-- v-on 事件监听 -->
<div id="app3">
<button @click="showAlert">v-on</button>
<input type="text" @keyup.enter="submit"/>
</div>
<script>
var vm = new Vue({
el: '#app3',
methods: {
showAlert: function () {
alert('v-on')
},
submit: function () {
alert('登录成功!')
}
}
})
</script>
2.6 v-for 列表循环
v-for 可以实现页面列表的渲染,常用来循环数组。
<!-- v-for 列表渲染-->
<div id="app4">
<div v-for="(item,key) in list" data-id="key">
索引是:{{key}},元素内容是:{{item}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app4',
data: {
list: ['a', 'b', 'c', 'd']
}
})
</script>
2.7 v-if 或v-show
控制元素显示或隐藏,属性为布尔值。
v-if:真正的条件渲染,会触发一些绑定的事件,惰性的,如果初始条件是false原始元素就不会进行渲染。条件不经常切换使用这个。
v-show:简单进行css样式切换,初始条件为false也会进行渲染,初始渲染开销大。条件经常改变的话常用这个。
<!-- v-if 和 v-show -->
<div id="app5">
<div v-if="isShow" style="background-color: #ccc;">我是v-if</div>
<div v-show="isShow" style="background-color: #ccc;">我是v-show</div>
<button @click="isShow=!isShow">显示/隐藏</button>
</div>
<script>
var vm = new Vue({
el: '#app5',
data: {
isShow: true
}
})
</script>
3.事件修饰符
修饰符 | 说明 |
---|---|
.stop | 阻止事件冒泡 |
.prevent | 阻止默认事件行为 |
.capture | 事件捕获 |
.self | 将事件绑定到自身,只有自身才能触发 |
.once | 事件只触发一次 |
3.1 stop 阻止事件冒泡
<!-- 阻止事件冒泡 -->
<div id="app1" @click="doParent" style="width: 100px;border: solid red 1px;">
<button @click="doThis">事件冒泡</button>
<br/>
<button @click.stop="doThis">阻止事件冒泡</button>
</div>
<script>
var vm = new Vue({
el: '#app1',
methods: {
doThis: function () {
alert('this');
},
doParent: function () {
alert('parent');
}
}
})
</script>
3.2 prevent 阻止默认行为
<!-- 阻止默认事件 -->
<div id="app2">
<a href="https://www.baidu.com">不阻止默认事件</a>
<br/>
<a href="https://www.baidu.com" @click.prevent>阻止默认事件</a>
</div>
<script>
var vm = new Vue({
el: '#app2'
})
</script>
3.3 capture 事件捕获
<!-- 改变冒泡顺序,事件由外向内 -->
<div id="app3" @click.capture="doParent" style="width: 100px;border: solid red 1px;">
<button @click="doThis">事件捕获</button>
</div>
<script>
var vm = new Vue({
el: '#app3',
methods: {
doThis: function () {
alert('this');
},
doParent: function () {
alert('parent');
}
}
})
</script>
3.4 self 自身触发
<!-- self 只有自身会触发时间,不会被冒泡触发 -->
<div id="app4" @click.self="doParents" style="width: 100px;height: 100px;background-color: #aaaa;">
a
<div @click="doSub" style="width: 70px;height: 70px;background-color: #5555;">
b
</div>
</div>
<script>
var vm = new Vue({
el: '#app4',
methods: {
doParents: function () {
console.log('调用了doParent');
},
doSub: function () {
console.log('调用了doSub');
}
}
})
</script>
3.5 once 只触发一次
<!-- once 事件只触发一次 -->
<div id="app5">
<button @click.once="doThis">只触发一次</button>
</div>
<script>
var vm = new Vue({
el: '#app5',
methods: {
doThis: function () {
console.log('只触发一次')
}
}
})
</script>
三、Vue组件
在Vue中,组件是构成页面中的独立结构单元,能够减少重复代码的编写,提高开发效率,降低代码之间的耦合程度,使项目更易维护和管理。
举例:如果页面中常常要有公司logo那么可以将logo定义为组件。
1.全局组件
在js内部使用**Vue.component(‘组件名’,{template:‘标签’})**可以定义全局组件
<div id="app">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<div id="app1">
<myComponent>aaa</myComponent>
</div>
<script>
// 全局组件
Vue.component('myComponent',//组件名称,命名的时候可以用驼峰命名法,引用的时候不能使用驼峰命名法,只能使用连接法
{
template: "<h2>这是一个全局组件</h2>"//模板就是组件的内容
}
);
Vue.component('my-abc',
{
// data是方法,该方法必须要有返回值,通常该返回值是给模板使用的
data() {
return {
count: 0
}
},
template: "<button v-on:click='count++'>被单击了{{count}}次</button>"
}
);
new Vue({
el: '#app'
});
new Vue({
el: '#app1'
})
</script>
2.局部组件
在Vue()内部使用components关键字定义自定义组件
<!-- 局部组件 -->
<div id="app2">
<my-abc></my-abc>
</div>
<script>
new Vue({
el: "#app2",
components: {
myAbc: {
template: "<p>这是一个局部组件</p>"
}
}
})
</script>
3.模板变量
将template模板使用变量装起来,使用的时候直接调用该变量即可。
<div id="app3">
<my-aaa></my-aaa>
</div>
<script>
//模板变量
var mytemp = {
template: '<h3>这是第二个局部组件</h3>'
};
new Vue({
el: '#app3',
components: {
myAaa: mytemp
}
});
</script>
4.template模板
template内的内容是使用字符串保存的很容易出错,所以我们可以使用template标签在html内部定义自定义组件的内容。
注意:template标签下只能有一个子标签
<!-- template 模板 -->
<div id="app4">
<my-comp></my-comp>
</div>
<template id="temp1">
<div>
<h1>这是一个标题</h1>
<p>这是一个段落:{{title}}</p>
<button v-on:click="show">单击我</button>
</div>
</template>
<script>
Vue.component('my-comp', {
template: '#temp1',
data() {
return {
title: '我是组件内的title'
}
},
methods: {
show: function () {
alert(this.title)
}
}
});
new Vue({
el: '#app4'
})
</script>
5.数据使用规则
vue定义的标签下面使用的自身data内的变量
template下自定义标签使用的变量是data()函数返回来的数据变量
注意:data()函数必须要有返回值
<div id="app5">
<p>{{title}}</p>
<my-comp2></my-comp2>
</div>
<template id="temp2">
<p>{{title}}</p>
</template>
<script>
Vue.component('my-comp2',
{
template: '#temp2',
data() {
return {
title: '这是组件中的data'
}
}
}
);
new Vue({
el: '#app5',
data: {
title: '我是vm实例的title'
}
})
</script>
6.组件传值
在Vue中,组件实例具有局部作用域。组件之间的数据传递需要借助一些工具。
6.1 props传值
props即道具,用来接受父组件中定义的数据,其值为数组,数组中是父组件传递的数据信息。
在调用**自定义组件(父组件)的时候使用“ 自定义属性=‘值’ ”的形式想模板中传递数据,子组件中使用“props:[‘name’]”**形式读取到父组件中的自定义属性值。
<!-- props 传值 -->
<div id="app">
<my-comp name="Tom"></my-comp>
</div>
<script>
Vue.component("my-comp",
{
props: ['name'],
template: '<h2>从组件中传递的值是:{{name}}</h2>'
}
);
new Vue({
el: '#app'
});
</script>
<div id="app1">
<my-comp1 props-message="父组件的数据"></my-comp1>
</div>
<template id="temp1">
<div>
<h3>父组件传给子组件</h3>
<p>通过props传递的,用props设置的值是组件(自定义标签)的属性名称</p>
<h4>父组件传递了:{{propsMessage}}</h4>
<h4>子组件自生的值:{{dataMessage}}</h4>
</div>
</template>
<script>
Vue.component('my-comp1',
{
template: '#temp1',
data() {
return {
dataMessage: '子组件中的数据'
}
},
props: ['propsMessage']
}
);
new Vue({
el: '#app1'
})
</script>
6.2 父组件用循环传值
案例一:通过循环创建网站列表
<div id="app">
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script>
Vue.component('todo-item', {
template: "<li>{{todo.text}}</li>",
props: ['todo']
});
new Vue({
el: '#app',
data: {
sites: [
{text: 'www.taobao.com'},
{text: 'www.jingdong.com'},
{text: 'www.baidu.com'},
]
}
})
</script>
案例二:通过循环创建子组件表格
<div id="app1">
<table>
<!--此处使用的是标题类-->
<student-list v-bind:stu="title"></student-list>
<!--此处使用的是遍历学生信息列表类-->
<student-list v-for="item in students" v-bind:stu="item"></student-list>
</table>
</div>
<template id="temp1">
<!--每一个模板为一行,行内有四个列:ID NAME AGE SEX-->
<tr>
<td style="border: 1px solid #000">{{stu.id}}</td>
<td style="border: 1px solid #000">{{stu.name}}</td>
<td style="border: 1px solid #000">{{stu.age}}</td>
<td style="border: 1px solid #000">{{stu.sex}}</td>
</tr>
</template>
<script>
Vue.component('student-list', {
template: '#temp1',
props: ['stu']
});
new Vue({
el: '#app1',
data: {
title: {
id: 'ID',
name: 'NAME',
age: 'AGE',
sex: 'SEX'
},
students: [
{id: '0001', name: '张三', age: 18, sex: '男'},
{id: '0002', name: '田媛媛', age: 18, sex: '女'},
{id: '0003', name: '陈雨', age: 20, sex: '男'},
]
}
})
</script>
6.3 组件多个属性传值
案例一:v-bind 基本多属性传值
<div id="app">
<p>第一个值<input type="text" v-model="s1"/></p>
<p>第二个值<input type="text" v-model="s2"/></p>
<p>第三个值<input type="text" v-model="s3"/></p>
<hr/>
<!--通过设置多个绑定来像子组件传递多个单值-->
<my-comp v-bind:attr1="s1" v-bind:attr2="s2" v-bind:attr3="s3"></my-comp>
</div>
<template id="my-temp">
<div>
<h3>多个属性的传值</h3>
<p>值1:{{attr1}}</p>
<p>值2:{{attr2}}</p>
<p>值3:{{attr3}}</p>
</div>
</template>
<script>
Vue.component('my-comp', {
template: '#my-temp',
props: ["attr1", "attr2", "attr3"]
});
new Vue({
el: '#app',
data: {
s1: '',
s2: '',
s3: ''
}
})
</script>
案例二:多个属性传值双向绑定
<div id="app">
<p>第一个值<input type="text" v-model="s1"/></p>
<p>第二个值<input type="text" v-model="s2"/></p>
<p>第三个值<input type="text" v-model="s3"/></p>
<hr/>
<my-comp v-bind:attr1="s1" v-bind:attr2="s2" v-bind:attr3="s3"></my-comp>
</div>
<template id="my-temp">
<div>
<h3>多个属性的传值</h3>
<p>值1:{{attr1}}</p>
<p>值2:{{attr2}}</p>
<p>值3:{{attr3}}</p>
<p>点击按钮后得到的值:{{content1}}</p>
<p>及时得到的值:{{content2}}</p>
<p>计算得到的值:{{contentx}}</p>
<button @click="show">按钮</button>
</div>
</template>
<script>
Vue.component('my-comp', {
template: '#my-temp',
props: ["attr1", "attr2", "attr3"],
data: function () {
return {
content1: "",
content2: ""
}
},
methods: {
//方法:按钮触发
show() {
this.content1 = this.attr1 + this.attr2 + this.attr3;
}
},
watch: {
//数据监听
attr1: function () {
this.content2 = this.attr1 + this.attr2 + this.attr3;
},
attr2: function () {
this.content2 = this.attr1 + this.attr2 + this.attr3;
},
attr3: function () {
this.content2 = this.attr1 + this.attr2 + this.attr3;
},
},
computed:{
//数据计算
contentx:function () {
return this.attr1 + this.attr2 + this.attr3;
}
}
});
new Vue({
el: '#app',
data: {
s1: '',
s2: '',
s3: ''
}
})
</script>
6.4 $emit方法 子组件像父组件传值
语法
this.$emit('处理方法', 数据);
案例
<div id="app">
<!--父组件-->
<parent></parent>
</div>
<template id="child">
<!--子组件模板-->
<div>
<button @click="click">传值</button>
<!--绑定了子组件中的message属性-->
<input type="text" v-model="message"/>
</div>
</template>
<script>
//父组件
Vue.component('parent', {
//父组件模板,子组件通过@childFn绑定了一个父组件事件处理方法,子组件可以通过该方法改变父组件中message的值
template: '<div><child @childFn="transContent"></child>子组件传来的值:{{message}}</div>',
data: function () {
return {
// 父组件中的message
message: ''
}
},
methods: {
//通过该事件处理方法可以修改父组件中message的值
transContent: function (payload) {
this.message = payload;
}
}
});
//子组件
Vue.component('child', {
template: '#child',
data: function () {
return {
//子组件中的message属性
message: '子组件的消息'
}
},
methods: {
click() {
//激活调用父组件中childFn绑定的事件,传的值是message
this.$emit('childFn', this.message);
//有点像java里面的super?
}
}
});
new Vue({
el: '#app'
})
</script>
7.组件切换
7.1 v-if v-else形式切换
<div id="app">
<label>
第一个页面内容
<input type="text" v-model="titleLogin"/>
</label>
<label>
第二个页面内容
<input type="text" v-model="titleRegister"/>
</label>
<br/>
<!--通过点击事件修改flag属性-->
<a href="#" @click.prevent="flag=true">登录页面</a>
<a href="#" @click.prevent="flag=false">注册页面</a>
<!--v-if v-else 配个标志属性进行简单的隐藏切换-->
<login v-if="flag" :title-name="titleLogin"></login>
<register v-else="flag" :title-name="titleRegister"></register>
</div>
<script>
// div的基本样式
Vue.component('login', {
props: ['title-name'],
template: '<div style="width: 100px;height: 100px;background-color: #00ff00;color: red">{{titleName}}</div>'
});
Vue.component('register', {
props: ['title-name'],
template: '<div style="width: 100px;height: 100px;background-color: #007ff0;color: yellow">{{titleName}}</div>'
});
new Vue({
el: '#app',
data: {
flag: true,
titleLogin: '登录',
titleRegister: '注册'
}
})
</script>
7.2 is属性组件切换
<div id="app">
<!-- 通过is属性修改模板的名字 -->
<a href="#" @click.prevent="comName='login'">登录页面</a>
<a href="#" @click.prevent="comName='register'">注册页面</a>
<!-- is绑定模板名字,被绑定的名字被修改则显示的模板也会被修改 -->
<component :is="comName"></component>
</div>
<script>
Vue.component('login', {
props: ['title-name'],
template: '<div style="width: 100px;height: 100px;background-color: #00ff00;color: red">{{登录页面}}</div>'
});
Vue.component('register', {
props: ['title-name'],
template: '<div style="width: 100px;height: 100px;background-color: #007ff0;color: yellow">{{注册页面}}</div>'
});
new Vue({
el: '#app',
data: {
comName: 'login',
}
})
</script>
四、Vue的生命周期
1.钩子函数
钩子函数用来描述Vue实例从创建到销毁的的整个生命周期
钩子 | 说明 |
---|---|
beforeCreate | 创建实例对象之前执行 |
created | 创建实例对象之后执行 |
beforeMount | 页面挂在成功之前执行 |
mounted | 页面挂在成功之后执行 |
beforeUpdate | 组件更新之前执行 |
updated | 组件更新之后执行 |
beforeDestroy | 实例销毁之前执行 |
destroyed | 实例销毁之后执行 |
1.1实施创建
<div id="app">{{msg}}</div>
<script>
new Vue({
el: '#app',
data: {
msg: '张三'
},
beforeCreate() {
console.log('实例创建之前');
// console.log(this.$data.msg);
},
created() {
console.log('实例创建之后');
console.log(this.$data.msg);
}
})
</script>
1.2实施销毁
<div id="app">
<!--ref是用来注册引用信息的-->
<div ref="self">{{msg}}</div>
</div>
<script>
new Vue({
el: '#app',
data: {
msg: '张三'
},
beforeDestroy(){
console.log('销毁之前');
console.log(this.$refs.self);
console.log(this.msg);
console.log(vm);
},
destroyed(){
console.log('销毁之后')
}
})
</script>
1.3实时更新
<div id="app">
<!--ref是用来注册引用信息的-->
<div v-if="isShow" ref="self">test</div>
<button @click="isShow=!isShow">更新</button>
</div>
<script>
new Vue({
el: '#app',
data: {
isShow: false
},
beforeUpdate() {
console.log('更新之前');
console.log(this.$refs.self);
},
updated() {
console.log('更新之后');
console.log(this.$refs.self);
}
})
</script>
1.4页面挂载
<div id="app">{{msg}}</div>
<script>
new Vue({
el: '#app',
data: {
msg: '张三'
},
beforeMount() {
//Vue与DOM关联之前
console.log('页面挂载之前');
console.log(this.$el.innerHTML);
},
mounted() {
//Vue与DOM关联之后
console.log('页面挂载之后');
console.log(this.$el.innerHTML);
},
beforeCreate() {
console.log('实例创建之前');
// console.log(this.$data.msg);
},
created() {
console.log('实例创建之后');
console.log(this.$data.msg);
}
})
</script>
1.5案例:实时显示时间
<div id="app">
<p id="time"></p>
<h3>格式化时间</h3>
<p>{{date|formatTime}}</p>
<p>
<button @click="stop">停止时间</button>
</p>
</div>
<script>
var p1 = document.querySelector('#time');
p1.innerHTML = new Date();
function parseDate(val) {
return val < 10 ? '0' + val : val;//小于10的数字,前面加0
}
var vm = new Vue({
el: '#app',
data: {
date: new Date(),
},
filters: {
formatTime: function (time) {
var year = time.getFullYear();
var month = parseDate(time.getMonth() + 1);
var day = parseDate(time.getDate());
var hours = parseDate(time.getHours());
var minute = parseDate(time.getMinutes());
var seconds = parseDate(time.getSeconds());
return year + '-' + month + '-' + day + " " + hours + ':' + minute + ':' + seconds;
}
},
created: function () {
var that = this;//保持作用域的一致,此处that就是当前对象
this.timmer = setInterval(function () {
that.date = new Date();
}, 1000);
},
methods: {
stop: function () {
clearInterval(this.timmer)
}
}
})
</script>
五、插槽
使用方法为:
- 在自定义组件标签中间写上预留内容。
- 在模板中使用标签,将预留内容引入。(假如模板中未使用标签,那么自定义标签中间的内容将会被忽略。)
1.插槽简单使用
当组件渲染的时候,将会被插槽预留的内容所替换,如下案例:
<div id="app">
<my-comp>
<h5>这是组件,在组件中写内容</h5>
</my-comp>
</div>
<template id="temp1">
<div>
<!-- 插槽就是模板预留的接口-->
<slot></slot><!--会替换为:<h5>这是组件,在组件中写内容</h5>-->
<p>这是模板内容,段落1</p>
<p>这是模板内容,段落2</p>
<p>这是模板内容,段落3</p>
<slot></slot>
<p>模板中的数据{{tempData}}</p>
<slot></slot>
</div>
</template>
<script>
Vue.component('my-comp',{
template: '#temp1',
data:function () {
return{
tempData: new Date()
}
}
});
new Vue({
el: "#app",
})
</script>
2.简单使用2
<div id="app">
<my-comp1>辣椒炒肉</my-comp1>
<my-comp1>辣椒炒蛋</my-comp1>
<my-comp1>空心菜</my-comp1>
<hr/>
<!--此处采用v-for循环遍历的形式将foods里面的值引入到自定义标签中-->
<my-comp1 v-for="item in foods">{{item.name}}</my-comp1>
<hr/>
<my-comp1></my-comp1>
</div>
<template id="temp1">
<dl>
<dt>
<!--通过slot标签将自定义标签中的内容引入进来-->
<slot>默认值,使用时没有给内容</slot>
<!--默认值:如果自定义标签内部没有内容
将会使用slot标签中间的内容-->
</dt>
<dd>中国湘菜,湘菜最强。</dd>
</dl>
</template>
<script>
Vue.component('my-comp1', {
template: '#temp1'
});
new Vue({
el: '#app',
data: {
foods: [
{name: '辣椒炒肉'},
{name: '辣椒炒蛋'},
{name: '辣子鸡'}
]
}
})
</script>
3.具名插槽
在定义自定义标签的预留内容的时候将标签加上slot='名字’属性,那么在标签调用插槽的时候,就需要用name='名字’去匹配使用。
<div id="app">
<my-compl>
<!--这个标签只有当slot标签name属性为'girl'的时候才会被匹配使用-->
<span style="background-color: pink;" slot="girl">漂亮、温柔、贤惠</span>
<!--这个标签只有当slot标签name属性为'boy'的时候才会被匹配使用-->
<span style="background-color: #007fff" slot="boy">帅气,高大,富有</span>
<!--默认的内容,如果没有匹配到的对象就会使用该默认内容-->
<div>
打工仔、干饭人、舔狗
</div>
</my-compl>
</div>
<template id="templ">
<div>
<h4>这个世界有男人和女人</h4>
<p>女人:
<!--匹配引入了自定义标签中,slot属性为‘girl'的标签-->
<slot name="girl"></slot>
</p>
<p>男人:
<!--匹配调用了自定义标签中,slot属性为‘boy'的标签-->
<slot name="boy"></slot>
</p>
<!--调用了自定义标签中的默认内容-->
<slot></slot>
</div>
</template>
<script>
Vue.component('my-compl', {
template: '#templ'
});
new Vue({
el: '#app'
})
</script>
4.案例:标题、正文、页脚匹配
此处我们也能看出,采用自定义控件+插槽的形式会使得控件格式更好规范添加。
<div id="app">
<my-compl>
<!--定义了标题、内容、页脚部分,还有默认内容-->
<h3 slot="headerName">这是我的主页</h3>
<p slot="mainName">这是我的主页内容</p>
<h4 slot="footerName">这是页脚部分</h4>
<p>今天是2021年的4月25日</p>
</my-compl>
</div>
<template id="templ">
<div>
<header>
<!--匹配标题部分-->
<slot name="headerName">页面标题</slot>
</header>
<mian>
<!--匹配正文部分-->
<slot name="mainName">正文部分</slot>
<slot>默认插槽</slot>
</mian>
<footer>
<!--匹配页脚部分-->
<slot name="footerName">页脚部分</slot>
</footer>
</div>
</template>
<script>
Vue.component('my-compl', {
template: '#templ'
});
new Vue({
el: '#app'
})
</script>
5.插槽作用域
通过slot-scope(插槽作用域)刻印进行一些数据的传递。slot-scope返回的是一个数据集合,里面有调用者的自定义属性的key:value集合
<div id="app">
<my-compl>
<template slot-scope="a">
{{a}}<!--输出结果为:{ "say": "你好", "n": "我是cy" }-->
</template>
</my-compl>
</div>
<script>
Vue.component('my-compl', {
template: '<div><slot say="你好" n="我是cy"></slot></div>'
});
new Vue({
el: '#app'
})
</script>
6.案例:匹配item格式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>插槽作用域</title>
<script src="../js/vue.js"></script>
<style>
.current {
color: orange;
}
</style>
</head>
<body>
<div id="app">
<!--父组件(在DOM中使用自定义组件)-->
<!--1.引入flist数组集合-->
<fruit :list="flist">
<!--5.获得调用者的属性集合-->
<template slot-scope="slotprops">
<!--6.内部判断插槽作用域内部元素的id值,并匹配样式-->
<strong v-if="slotprops.info.id==2" class="current">
{{slotprops.info.name}}
</strong>
<span v-else>{{slotprops.info.name}}</span>
</template>
</fruit>
</div>
<!--组件部分-->
<template id="temp">
<div>
<ul>
<!--3.通过循环遍历数组集合-->
<li :key="item.id" v-for="item in list">
<!--4.将item(集合数据)绑定到插槽作用域里面去,格式为info:{id:'',name:''}-->
<slot :info="item"></slot>
</li>
</ul>
</div>
</template>
<script>
Vue.component('fruit', {
template: '#temp',
props: ['list'],//2.将父组件的属性list传到子组件
});
new Vue({
el: "#app",
data: {
//数据集合
flist: [
{id: 1, name: 'apple'},
{id: 2, name: 'banana'},
{id: 3, name: 'orange'},
]
}
})
</script>
</body>
</html>
7.具名插槽结合使用
<div id="app">
<!--1.获得vue里面的data-->
<my-comp :items="items">
<!--4.引用具名插槽,填入数据-->
<template slot="item" scope="pro">
<li>
{{pro.text}}--{{pro}}
<!--
输出结果:
示例1--{ "text": "示例1" }
示例2--{ "text": "示例2" }
示例3--{ "text": "示例3" }
-->
</li>
</template>
</my-comp>
</div>
<template id="temp">
<div>
<ul>
<!--3.得到数据列表items,并遍历items,绑定text属性-->
<slot name="item" v-for="item in items" :text="item.text"></slot>
</ul>
</div>
</template>
<script>
Vue.component('my-comp', {
template: '#temp',
//2.数据传递,传递到子组件
props: ['items']
});
new Vue({
el: '#app',
data: {
items: [
{text: '示例1'},
{text: '示例2'},
{text: '示例3'},
],
}
})
</script>
8.具名插槽默认内容
<div id="app">
<my-comp>
<!--为空的时候不执行slot内的-->
</my-comp>
<my-comp>
<!--有调用的时候启用slot,slot内部的则不启用-->
<template slot-scope="myslot">
<span>
{{myslot.datail.join("-")}}
</span>
</template>
</my-comp>
</div>
<template id="temp">
<div>
<slot :datail="books">
<!--slot被调用的时候,这里面的默认内容就不会显示-->
<ul>
<li v-for="item in books">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
Vue.component('my-comp', {
template: '#temp',
data() {
return {
books: [
'唐诗三百首',
'宋词',
'元曲',
'小说',
]
}
}
});
new Vue({
el: '#app',
data: {
books: '父组件数据'
}
})
</script>