Vue.js初识
Vue(发音为/vjuː/,类似于view)是用于构建用户界面的 渐进框架。与其他整体框架不同,Vue从头开始设计以逐渐采用。核心库仅集中在视图层,并且易于拾取并与其他库或现有项目集成。另一方面,当与现代工具和支持库结合使用时,Vue也完全能够为复杂的单页应用程序提供支持。
入门案例(通过script标签引入):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue学习</title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id = "mydiv">
<h1>{{info}}</h1>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
info:'Hello World!'
}
});
</script>
</body>
</html>
效果:
v-once属性:
作用就是定义它的元素或组件只会渲染一次
<h1>{{info}}</h1> <!-- 通过v-once语法只会渲染一次 -->
<h1 v-once>{{info}}</h1>
v-pre属性:
v-pre指令使用可以跳过Vue编译过程
<h1>{{info}}</h1>
<h1 v-pre>{{info}}</h1> <!-- 这里只会输出{{info}}-->
v-text属性:
输出为文本格式
<h1>{{info}}</h1> <!-- 这种方式适用于可以在首尾添加字符串 -->
<h1 v-text="info">这里会被覆盖</h1> <!-- 这种方式会覆盖标签的value -->
v-html属性:
输出解析为HTML格式
<div id = "mydiv">
<div v-html="info"></div>
</div>
var vm = new Vue({
el:'#mydiv',
data:{
info:'<h1>一个大标题</h1>'
}
});
v-bind属性:
绑定属性的指令,会将内容解析为js表达式,这里需要注意的是,不同于v-model,这里的v-bind是单向绑定。
<div id = "mydiv">
<input v-bind:title="mytitle" value="按钮1" type = "button" />
<input :title="mytitle" value="按钮2" type="button"/> <!-- 利用':'简写 -->
</div>
var vm = new Vue({
el:'#mydiv',
data:{
mytitle:'一个按钮'
}
});
对class元素进行绑定
<style type="text/css">
.style1{
color:red;
font-size:20px;
}
.style2{
color:blue;
font-size:40px;
}
</style>
<div id="app">
<h2 :class="{style1: isStyle1, style2 : isStyle2}">{{firstName + " " + lastName}}</h2>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
firstName:"世界",
lastName:"你好",
isStyle1:true,
isStyle2:false,
}
})
</script>
v-on属性:
绑定方法的指令,会将内容解析为js表达式
<div id = "mydiv">
<!-- 一下两个结果一致 -->
<input value="按钮1" v-on:click="sayHello" type="button"/>
<input value="按钮2" @click="sayHello" type="button"/> <!-- 简写 -->
</div>
var vm = new Vue({
el:'#mydiv',
methods:{
sayHello:function(){
alert("你好 世界!");
}
}
});
计算属性computed:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<h1>计算属性的值为:{{fullName}}</h1>
<h1>计算属性的值为:{{totalPrice}}</h1>
</div>
<script>
const app = new Vue({
el:"#app",
data: {
books:[{id:1001,name:"三体一",price:80},
{id:1002,name:"三体二",price:100},
{id:1003,name:"三体三",price:90}],
firstName:'你好',
lastName:'世界'
},
computed:{
// 实现计算属性的第一种方式(完整写法)
fullName:{
get:function(){
return this.firstName+" "+this.lastName
},
set:function (newValue) {
this.firstName = newValue.split(' ')[0];
this.lastName = newValue.split(' ')[1];
}
},
// 实现计算属性的第二种方式,是第一种方式的getter方法简写
totalPrice:function(){
let result = 0;
for(let i = 0 ; i<this.books.length ; i++){
result += this.books[i].price
}
return result;
}
}
})
</script>
</body>
</html>
这里computed计算属性和methods方法区别:
重复多次调用时,methods会多次调用方法,而computed只会调用一次,显然使用computed效率会更高一些
跑马灯效果案例实现:
点击一次字体,跑马灯效果,再次点击,恢复原始暂停效果
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue学习</title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id = "mydiv">
<h1 v-on:click="circulate" v-text = "info"></h1>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
info:'你好 世界!',
intervalid:null,
times:0
},
methods:{
circulate(){
if(this.times%2){
var _this = this // 如果不写此处,则应该使用箭头函数 () => {}
this.intervalid = setInterval(function(){
var temp1 = _this.info.substring(0,1)
var temp2 = _this.info.substring(1)
_this.info = temp2+temp1
},300)
}else{
clearInterval(this.intervalid) // 删除计时器
this.intervalid = null
}
this.times++
}
}
});
</script>
</body>
</html>
效果:
事件修饰符
.stop:
阻止冒泡修饰符
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue学习</title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
#mydiv{
height: 200px;
background-color: cornflowerblue;
}
</style>
</head>
<body>
<div id = "mydiv" @click="outDivClick">
<div align = "center" v-on:click="inDivClick" v-text = "info"></div>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
info:'你好 世界!'
},
methods:{
outDivClick(){
console.log("外部的div响应")
},
inDivClick(){
console.log("内部的div响应")
}
}
});
</script>
</body>
</html>
点击字体,浏览器控制台会先触发内部div,然后再触发外部div
如果不希望出现以上效果,则只要再加上.stop即可:
<div align = "center" v-on:click.stop="inDivClick" v-text = "info"></div>
点击后,只会出现如下效果:
.prevent:
阻止默认程序的运行
<div id = "mydiv">
<a href="http://localhost:8080" @click.prevent="aClick">一个链接入口</a>
</div>
const vm = new Vue({
el:'#mydiv',
methods:{
aClick(){
console.log("阻止重定向")
}
}
});
.capture:
<div id = "mydiv" @click.capture="outDivClick">
<div align = "center" v-on:click="inDivClick" v-text = "info"></div>
</div>
结果:
点击字体,浏览器控制台会先触发外部div,然后再触发内部div
.self:
<div id = "mydiv" @click.self="outDivClick">
<div align = "center" v-on:click="inDivClick" v-text = "info"></div>
</div>
结果:
点击字体,只会触发内部div事件
.once:
<div id = "mydiv">
<a href="http://localhost:8080" @click.prevent.once="aClick">一个链接入口</a>
</div>
var vm = new Vue({
el:'#mydiv',
methods:{
aClick(){
console.log("只会阻止一次重定向")
}
}
});
@keyup/@keydown事件:
<div id="app">
<input type="text" @keyup.enter="keyUp">
<input type="text" @keyup="keyUp">
</div>
<script>
const app = new Vue({
el:"#app",
methods:{
keyUp(){
console.log("回车键盘释放产生动作");
}
}
})
</script>
第一个
v-model:
v-bind只能实现数据的单向绑定,而v-model是唯一一个可以实现双向数据绑定的属性
单向绑定演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue学习</title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id = "mydiv">
<input v-bind:value="info" />
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
info:'你好 世界!'
}
});
</script>
</body>
</html>
以下结果可以说明,采用v-bind只能实现从M层绑定到V层,而不能实现V层绑定到M层
双向绑定演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue学习</title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id = "mydiv">
<input v-model:value="info" />
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
info:'你好 世界!'
}
});
</script>
</body>
</html>
使用v-model,不仅M层的数据绑定到V层,V层的数据同样绑定到了M层
对于复选框,如果是一个则为逻辑值,如果是多个则绑定到同一个数组中:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<input type="checkbox" v-model="checked" id="choice"/>
<label for="choice">{{checked}}</label>
<br><br>
<input type="checkbox" v-model="checkedNames" value="看看书籍" id="readBook"/>
<label for="readBook">看看书籍</label>
<input type="checkbox" v-model="checkedNames" value="听听音乐" id="listenMusic"/>
<label for="listenMusic">听听音乐</label>
<input type="checkbox" v-model="checkedNames" value="敲敲代码" id="knockCode"/>
<label for="knockCode">敲敲代码</label>
<p>{{checkedNames}}</p>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
checked:false,
checkedNames:[]
}
})
</script>
</body>
</html>
结果:
对于select列表:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
<p>你选择了{{selected}}</p>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
selected:""
}
})
</script>
</body>
</html>
结果:
对于单选按钮:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<input type="radio" value="一" v-model="picked" id="choiceOne"/>
<label for="choiceOne">选择一</label>
<input type="radio" value="二" v-model="picked" id="choiceTwo"/>
<label for="choiceTwo">选择二</label>
<p>你的选择是:{{picked}}</p>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
picked:"一"
}
})
</script>
</body>
</html>
结果:
注:v-model只能应用于表单元素中
v-model的.lazy修饰符:
只有当回车或者失去焦点才会将数据绑定到M层中
<div id="app">
<input type="text" v-model.lazy="info">
<h1>{{info}}</h1>
</div>
<script>
// 常量的含义是指向的对象不能发生改变,但是对象的属性是可以改变的
const app = new Vue({
el:"#app",
data: {
info:"你好 世界",
}
})
</script>
v-model的.number修饰符:
将双向绑定的默认string类型转化number类型
<div id="app">
<input type="number" v-model.number="id">
<h1>学号:{{id}},学号类型:{{typeof id}}</h1>
</div>
<script>
// 常量的含义是指向的对象不能发生改变,但是对象的属性是可以改变的
const app = new Vue({
el:"#app",
data: {
id:0
}
})
</script>
v-model的.trim修饰符:
剪除输入框中的左右端所有空格
<div id="app">
<input type="text" v-model.trim="name">
<h1>姓名:{{name}}</h1>
</div>
<script>
// 常量的含义是指向的对象不能发生改变,但是对象的属性是可以改变的
const app = new Vue({
el:"#app",
data: {
name:''
}
})
</script>
计算器效果案例实现:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue学习</title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div align="center">
<h2 style="color:cadetblue">简易计算器</h2>
<div id = "calculator">
<table border="1" cellspacing="0" bgcolor="cornflowerblue">
<tr>
<td colspan="4" ><input type = "text" v-model="number" ></td>
</tr>
<tr align = "center">
<td ><input style="width: 100%;height:100%" value = "÷" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "7" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "8" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "9" v-on:click="pushSign($event)" type = "button"></input></td>
</tr>
<tr align = "center">
<td><input style="width: 100%;height:100%" value = "×" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "4" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "5" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "6" v-on:click="pushSign($event)" type = "button"></input></td>
</tr>
<tr align = "center">
<td><input style="width: 100%;height:100%" value = "-" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "3" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "2" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "1" v-on:click="pushSign($event)" type = "button"></input></td>
</tr>
<tr align = "center">
<td><input style="width: 100%;height:100%" value = "+" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "0" v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "." v-on:click="pushSign($event)" type = "button"></input></td>
<td><input style="width: 100%;height:100%" value = "=" v-on:click="compute($event)" type = "button"></input></td>
</tr>
</table>
</div>
</div>
<script>
var vm = new Vue({
el:'#calculator',
data:{
number:'',
sign:0,
divCnt:0,
subCnt:0,
subCnt:0,
addCnt:0
},
methods:{
pushSign(event){
var str = event.currentTarget.value
this.number = this.number+str
},
compute(){
var div = this.number.indexOf('÷')
var mul = this.number.indexOf('×')
var sub = this.number.indexOf('-')
var add = this.number.indexOf('+')
if(div != -1 && mul == -1 && sub == -1 && add == -1){
var num1 = parseFloat(this.number.substring(0,div))
var num2 = parseFloat(this.number.substring(div+1))
this.number = num1/num2
}else if(div == -1 && mul != -1 && sub == -1 && add == -1){
var num1 = parseFloat(this.number.substring(0,mul))
var num2 = parseFloat(this.number.substring(mul+1))
this.number = num1*num2
}else if(div == -1 && mul == -1 && sub != -1 && add == -1){
var num1 = parseFloat(this.number.substring(0,sub))
var num2 = parseFloat(this.number.substring(sub+1))
this.number = num1-num2
}else if(div == -1 && mul == -1 && sub == -1 && add != -1){
var num1 = parseFloat(this.number.substring(0,add))
var num2 = parseFloat(this.number.substring(add+1))
this.number = num1+num2
}else{
this.number = '' // 清空内容
}
}
}
});
</script>
</body>
</html>
效果:
通过属性绑定元素使用class类样式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
.size{
font-size: 20px;
}
.italic{
font-style: italic;
}
.color1{
color: blue;
}
.color2{
color: red;
}
</style>
</head>
<body>
<div id = "mydiv">
<!-- 使用三元表达式 -->
<p :class="['size','italic',colorFlag?'color1':'color2']" @click="updateColor">一个会改变颜色的段落</p>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
colorFlag:false,
times:0
},
methods:{
updateColor(){
if(this.times%2){
this.colorFlag = true
}else{
this.colorFlag = false
}
this.times++
}
}
})
</script>
</body>
</html>
效果:
每次点击字体都会改变颜色
也可以直接使用对象:
<div id = "mydiv">
<p :class="classObj">一个普通的段落</p>
</div>
var vm = new Vue({
el:'#mydiv',
data:{
classObj:{
size:true,
italic:true
}
}
})
通过属性绑定元素使用style样式
<div id = "mydiv">
<p :style="[styleObj1,styleObj2]">一个普通的段落</p>
</div>
var vm = new Vue({
el:'#mydiv',
data:{
styleObj1:{
color: 'blue',
'font-size':20
},
styleObj2:{
'font-style':'italic',
}
}
})
v-for:
对于遍历js数组
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id = "mydiv">
<p v-for="(item,i) in items">元素值:{{item}} 索引值:{{i}}</p>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
items:[1,2,3,4,5,6,7,8,9]
}
})
</script>
</body>
</html>
结果:
对于遍历对象数组
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id = "mydiv">
<p v-for="(user,i) in users">索引为:{{i}} 姓名为:{{user.name}} 年龄为:{{user.age}}</p>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
users:[{
name:'张一',
age:20
},{
name:'张二',
age:21
},{
name:'张三',
age:22
}]
}
})
</script>
</body>
</html>
结果:
对于遍历对象
<div id = "mydiv">
<p v-for="(value,key,i) in user">索引:{{i}} 值:{{value}} 键:{{key}}</p>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
user:{
name:'张三',
age:20,
}
}
})
</script>
对于次数限制的v-for
<div id = "mydiv">
<p v-for="count in 10">这是第{{count}}次迭代</p>
</div>
<script>
var vm = new Vue({
el:'#mydiv'
})
</script>
v-if & v-else-if & v-else:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<h1 v-if="flag === 'A'">Result is A</h1>
<h1 v-else-if="flag === 'B'">Result is B</h1>
<h1 v-else-if="flag === 'C'">Result is C</h1>
<h1 v-else-if="flag === 'D'">Result is D</h1>
<h1 v-else>Result is other</h1>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
flag: 'A'
}
})
</script>
</body>
</html>
v-if & v-show:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id = "mydiv">
<input type = "button" value = "按钮" @click="onclick"/>
<h2 v-if="flag">一个会消失的标题</h2>
<h2 v-show="flag">一个会消失的标题</h2>
</div>
<script>
var vm = new Vue({
el:'#mydiv',
data:{
flag:true
},
methods:{
onclick(){
this.flag = !this.flag
}
}
})
</script>
</body>
</html>
结果:
点击后:
当需要显示与隐藏元素组件很频繁时,使用v-show
当只有一次切换时,通过使用v-if
Vue Ajax(Axios)的基本使用
Axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,Vue 官方建议用 axios 代替 vue-resourse。
首先需要引入:
<script src="js/axios.min.js"></script>
举例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="js/axios.min.js"></script>
</head>
<body>
<div id = "app">
<div>姓名:{{info.name}}</div>
<div>年龄:{{info.age}}</div>
<div>地址:{{info.address.country}},{{info.address.province}}省</div>
<ul>
<li v-for="item in info.contacts">方式:{{item.kind}},号码:{{item.number}}</li>
</ul>
</div>
<script>
var app = new Vue({
el:"#app",
data(){
return {
info:null
}
},
mounted(){
axios
.get("data.json")
.then(response => (this.info=response.data))
}
})
</script>
</body>
</html>
相应的json数据如下:
{
"name":"张三",
"age":55,
"address":{
"country":"中国",
"province":"湖南"
},
"contacts":[
{
"kind":"WeChat",
"number":"00000"
},
{
"kind":"QQ",
"number":"00001"
},
{
"kind":"Email",
"number":"00003@email.com"
}
]
}
结果:
实现一个简单购物车功能:
需求简介: 显示书籍的名称,日期,价格,数量,增加和减少商品数量,移除该书籍所有显示信息,,总价格实时显示,当所有的书籍都移除后,显示为'书籍购物车为空'
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>购物车案例</title>
<link rel="stylesheet" href="../css/bookTable.css" type="text/css">
</head>
<body>
<script src="../js/vue.js"></script>
<br>
<div id="app">
<div v-if="!isEmpty">
<table border="1" cellspacing="0">
<thead>
<tr align="center" >
<th></th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tr v-for="(item,index) in books" align="center">
<td> {{index+1}} </td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{item.price | priceFilter}}</td>
<td><span><button @click="decrease(index)" :disabled="item.number <= 1">-</button> {{item.number}} <button @click="increase(index)">+</button></span></td>
<td><button @click="remove(index)">移除</button></td>
</tr>
</table>
<h1 align="center">总价格为:{{totalPrice | priceFilter}}</h1>
</div>
<h1 v-else align="center">书籍购物车为空</h1>
</div>
<script>
const app = new Vue({
el:"#app",
data: {
books:[
{name:"数据结构",date:"2018-2",price:184.50,number:1},
{name:"计算机组成原理",date:"2019-3",price:151.50,number:1},
{name:"计算机网络",date:"2020-4",price:127.50,number:1},
{name:"操作系统",date:"2021-5",price:111.00,number:1}
],
total:-1,
isEmpty:false
},
mounted:function(){
// 初始化书籍种类数量参数
this.total = this.books.length
},
methods:{
decrease(index){
this.books[index].number--
},
increase(index){
this.books[index].number++
},
remove(index){
this.books.splice(index,1) // 只有这种形式的才能保持监听删除,实时响应
this.total -- // 书籍种类数减少一
if(this.total == 0){
this.isEmpty = true
}
}
},
computed:{
totalPrice(){
let result = 0
for(let i = 0 ; i<this.books.length ; i++){
result += this.books[i].number*this.books[i].price
}
return result
}
},
filters:{
// 过滤器定义
priceFilter(price){
return price.toFixed(2)+"元"
}
}
})
</script>
</body>
</html>
bookTable.css:
table
{
border-collapse: collapse;
margin: 0 auto;
text-align: center;
}
table td, table th
{
border: 1px solid #cad9ea;
color: #666;
height: 30px;
}
table thead th
{
background-color: #CCE8EB;
width: 100px;
}
table tr:nth-child(odd)
{
background: #fff;
}
table tr:nth-child(even)
{
background: #F5FAFA;
}
最终效果
点击’计算机网络’的购买数量加号后显示:
然后点击移除’计算机网络’后显示:
最后当所有书籍都移除后显示:
组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app1">
<my-component></my-component>
<my-component></my-component>
</div>
<div id="app2">
<my-component></my-component>
<my-component></my-component>
</div>
<script>
// 使用``可以直接换行
// 1.创建组件
const component = Vue.extend({
template:`
<div>
<h1>我是标题</h1>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
`
})
// 2.注册全局组件方式
// Vue.component('my-component',component)
// 常量的含义是指向的对象不能发生改变,但是对象的属性是可以改变的
const app1 = new Vue({
el:"#app1",
components:{
// 注册局部组件,其中key代表标签名,value代表所创建的组件
'my-component': component
}
})
// 常量的含义是指向的对象不能发生改变,但是对象的属性是可以改变的
const app2 = new Vue({
el:"#app2",
})
</script>
</body>
</html>
创建父子组件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app1">
<my-component2></my-component2>
<my-component2></my-component2>
</div>
<script>
// 使用``可以直接换行
// 创建子组件
const component1 = Vue.extend({
template:`
<div>
<h1 style="color:blue">我是标题一</h1>
<p>我是内容一</p>
<p>我是内容二</p>
</div>
`
})
// 创建父组件
const component2 = Vue.extend({
template:`
<div>
<my-component1></my-component1>
<h1 style="color:red">我是标题二</h1>
<p>我是内容一</p>
<p>我是内容二</p>
</div>
`,
components:{
'my-component1':component1
}
})
// root组件
const app1 = new Vue({
el:"#app1",
components:{
// 注册局部组件,其中key代表标签名,value代表所创建的组件
'my-component2': component2,
}
})
</script>
</body>
</html>
语法糖形式:
const component2 = Vue.extend({
template:`
<div>
<my-component1></my-component1>
<h1 style="color:red">我是标题二</h1>
<p>我是内容一</p>
<p>我是内容二</p>
</div>
`,
components:{
'my-component1':{ //语法糖形式注册局部子组件,直接省略Vue.extend()的调用过程
template:`
<div>
<h1 style="color:blue">我是标题一</h1>
<p>我是内容一</p>
<p>我是内容二</p>
</div>
`
}
}
})
模板分离写法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<component1></component1>
<br>
<component2></component2>
</div>
<!-- 1.通过script标签 -->
<script type="text/x-template" id="component1">
<div>
<h1>我是标题</h1>
<p>我是内容</p>
</div>
</script>
<!-- 2.通过template标签 -->
<template id="component2">
<div>
<h1>我是标题</h1>
<p>我是内容</p>
</div>
</template>
<script>
Vue.component('component1',{
template:'#component1'
})
Vue.component('component2',{
template:'#component2'
})
const app = new Vue({
el:"#app",
})
</script>
</body>
</html>
组件data为函数:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<template id="counter">
<div>
<h1>当前的计数值为:{{count}}</h1>
<button @click="increase">+</button>
<button @click="decrease">-</button>
</div>
</template>
<script>
Vue.component('counter',{
template:'#counter',
data(){
return {
count:0
}
},
methods:{
increase(){
this.count ++
},
decrease(){
this.count --
}
}
})
const app = new Vue({
el:"#app",
})
</script>
</body>
</html>
父对子组件通信(props):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<books_tag></books_tag> <!-- 未传递数据时 -->
<books_tag :books="books"></books_tag> <!-- 传递数据时 -->
<books_tag :books="books" :book-info-title="info"></books_tag> <!-- 传递数据时 -->
</div>
<template id="books_template">
<div>
<h1>标题:{{bookInfoTitle}}</h1>
<ul>
<li v-for="(book,index) in books">{{index+1}}.书籍名称:{{book.name}},书籍价格:{{book.price}}</li>
</ul>
</div>
</template>
<script>
// 当前作为子组件
const mybooks = {
template:'#books_template',
props:{
// 自定义该子组件的属性
books:{
// 要求子组件books属性必须为数组类型,当父组件未传递数据时,默认为空数组,允许不必要父组件传递子组件传递数据
type:Array,
// 类型是对象或者数组时,默认值必须是一个函数生成的对象或者数组
default(){
return [{name:"无",price:0}]
},
required:false
},
bookInfoTitle:{ // 采用驼峰式命名时,标签属性由于对大小写不敏感,所以需要加'-'符号
type:String,
default:"",
required:false
}
}
}
// 当前作为根(父)组件
const app = new Vue({
el:"#app",
data:{
books:[{name:"三体一",price:101.5},
{name:"三体二",price:202.5},
{name:"三体三",price:303.5}],
info:"书籍信息"
},
components:{
// 将mybooks变量作为子组件
books_tag:mybooks
}
})
</script>
</body>
</html>
子对父组件通信($emit):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<child-book @child-book-click="fatherBookClick"></child-book>
<h1 v-if="book.name != undefined">父组件接收到的书籍信息,书籍名称:{{book.name}},书籍价格:{{book.price}}元。</h1>
</div>
<template id="child-template">
<div>
<br>
<br>
<button v-for="item in books" @click="childBtnClick(item)">{{item.name}}</button>
</div>
</template>
<script>
// 创建子组件
const child = {
template:'#child-template',
data(){
// 返回一个创建的对象
return {books:[{name:"三体一",price:101.5},
{name:"三体二",price:202.5},
{name:"三体三",price:303.5}]}
},
methods:{
childBtnClick(item){
this.$emit('child-book-click',item)
}
}
}
// 创建父组件
const app = new Vue({
el:"#app",
data: {
book:{},
},
components:{
// 注册子组件
'child-book':child
},
methods:{
fatherBookClick(item){
// 这里默认接收到子组件中发射的对象,即不需要 函数(参数) 形式亦可
this.book = item
}
}
})
</script>
</body>
</html>
点击’三体二’按键
父子组件之间的访问方式
父访问子($children或$refs):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<child_label ></child_label>
<child_label ></child_label>
<child_label ref="special"></child_label> <!-- reference形式实现父对子的访问 -->
<button @click="fatherAccess">访问子组件属性值和方法</button>
<button @click="fatherModify">修改子组件属性值</button>
</div>
<template id="child-template">
<div>
<h1>父组件访问子组件</h1>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
</div>
</template>
<script>
// 创建子组件
const child = {
template:'#child-template',
data(){
return {
name:"张三",
age:20
}
},
methods:{
sayHello(){
console.log("你好 世界!");
}
}
}
// 创建父组件
const app = new Vue({
el:"#app",
components:{
// 注册子组件
'child_label':child
},
methods:{
fatherAccess(){
console.log("$children访问形式");
for(let child of this.$children){
child.sayHello()
console.log("姓名:",child.name,"年龄:",child.age);
}
console.log("$refs访问形式");
console.log(this.$refs.special.name); // 优点:不依赖于组件的数组位置,常用
},
fatherModify(){
for(let child of this.$children){
child.name = "王五"
child.age = 21
}
}
}
})
</script>
</body>
</html>
点击第一个按钮后,控制台输出为:
然后点击第二个按钮后再次点击第一个按钮,改变所有子组件属性值:
子访问父($parent和$root):
很少用到,因为耦合度的原因
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<h1>我是父组件</h1>
<son_label></son_label>
</div>
<template id="son-template">
<div>
<h1>我是子组件</h1>
<grandson_label></grandson_label>
</div>
</template>
<template id="garandson-template">
<div>
<h1>我是子子组件</h1>
<button @click="sayHello">你好</button>
</div>
</template>
<script>
// 创建子子组件
const grandson = {
template:'#garandson-template',
data(){
return {
name:"张三",
age:20
}
},
methods:{
sayHello(){
this.$root.sayHello() // 调用根组件方法
this.$parent.sayHello() // 调用父组件方法
console.log("你好,我是",this.name);
}
}
}
// 创建子组件
const son = {
template:'#son-template',
data(){
return {
name:"张二",
age:27
}
},
methods: {
sayHello() {
console.log("你好,我是", this.name, ",如今", this.age, "岁了。");
}
},
components:{
// 组件注册
grandson_label:grandson
}
}
// 创建父组件
const app = new Vue({
el:"#app",
data:{
name:"张一",
age:50
},
components:{
// 注册子组件
'son_label':son
},
methods:{
sayHello(){
console.log("你好,我是",this.name,",如今",this.age,"岁了。");
}
}
})
</script>
</body>
</html>
插槽(slot)的基本使用方式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<child-label></child-label>
<child-label><input type="text" value="我是输入框"></child-label>
<child-label></child-label>
<child-label><a href="https//www.baidu.com" >我是a标签</a></child-label>
<child-label></child-label>
</div>
<template id="child-template">
<div>
<h1>我是标题</h1>
<p>我是内容</p>
<slot><button>我是按钮</button></slot> <!-- 默认插槽为button标签 -->
</div>
</template>
<script>
const app = new Vue({
el:"#app",
components:{
"child-label":{
template:"#child-template"
}
}
})
</script>
</body>
</html>
具名插槽的使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<child-label></child-label>
<hr>
<child-label>
<h1 slot="two">我是标题二</h1>
<h1 slot="four">我是标题四</h1>
</child-label>
</div>
<!-- 2.通过template标签 -->
<template id="child-template">
<div>
<slot name="one"><button>我是按钮一</button></slot> <!-- 默认插槽为button标签 -->
<slot name="two"><button>我是按钮二</button></slot>
<slot name="three"><button>我是按钮三</button></slot>
<slot name="four"><button>我是按钮四</button></slot>
</div>
</template>
<script>
const app = new Vue({
el:"#app",
components:{
"child-label":{
template:"#child-template"
}
}
})
</script>
</body>
</html>
作用域插槽的基本使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/vue.js"></script>
<div id="app">
<!-- 默认插槽格式 -->
<child-label></child-label>
<!-- 更换插槽风格样式 -->
<child-label>
<div slot-scope="scope"> <!-- 子组件提供给父组件的出口 Vue版本2.6-->
<h2 v-for="book in scope.books">书籍名称:{{book.name}},书籍价格:{{book.price}}</h2>
</div>
</child-label>
</div>
<template id="child-template">
<div>
<slot :books="books"> <!-- 子组件供给父组件的数据入口 -->
<ul>
<li v-for="book in books">书籍名称:{{book.name}},书籍价格:{{book.price}}</li>
</ul>
</slot>
</div>
</template>
<script>
const app = new Vue({
el:"#app",
components:{
"child-label":{
template:"#child-template",
data(){
return{
books:[{name:"三体一",price:101.5},
{name:"三体二",price:202.5},
{name:"三体三",price:303.5}]
}
},
}
}
})
</script>
</body>
</html>
模块化基础(ES6导入导出):
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 这里需要是module类型支持 -->
<script src="js/a.js" type="module"></script>
<script src="js/b.js" type="module"></script>
</body>
</html>
a.js:
// 第一种导出方式:属性导出
export let name = "张三"
export let age = 18
let student = {
name,
age
}
function sayHello(student){
console.log("你好,"+student.name+"!");
}
// 第二种导出方式:对象导出
export {
student, sayHello
}
// 第三种导出方式:函数导出
export function getAge(student) {
return student.age
}
// 第四种导出方式:类导出
export class Programmer{
typeCode(){
console.log("敲代码中...");
}
}
// 默认导出方式:只能唯一一个,其导出可以自定义命名/包括以上的所有类型
const id = 1000;
export default id
b.js:
// 导入方式一:
import {student,sayHello} from "./a.js";
sayHello(student)
import {name,age} from "./a.js";
console.log("学生姓名:",name,",学生年龄:",age);
import {getAge} from "./a.js";
console.log(getAge(student));
import {Programmer} from "./a.js";
const p = new Programmer()
p.typeCode()
// 导出default,将id作为number
import number from "./a.js"
console.log(number);
// 导入方式二:自定义选择导入
import * as all from "./a.js"
all.sayHello(all.student)