Vue.js 基础入门

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>&nbsp;{{index+1}}&nbsp;</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)

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值