# 02 插值的操作
# 01 Mustache语法
<body>
<div id ="app">
<h2>{{message}}</h2>
<h2>{{message}},李银河</h2>
<h2>{{firstName + lastName}}</h2>
<h2>{{firstName + ' ' + lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<h2>{{counter * 2}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
firstName: 'kobe',
lastName: 'bryant',
counter: 100
},
methods: {}
});
</script>
</body>
# 02 v-once
v-once不动态加载
<div id ="app">
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: "你好啊!"
},
methods: {}
});
</script>
# 03 v-html
直接展示html
<div id ="app">
<h2 v-html="url"></h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: "你好啊",
url: '<a href="http://www.baidu.com">baidu.com</a>'
},
methods: {}
});
</script>
# 04 v-text
<div id ="app">
<h2>{{message}},李银河!</h2>
<h2 v-text='message'>,李银河</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {}
});
</script>
# 05 v-pre
原封不动的解析
<div id ="app">
<h2>{{message}}</h2>
<h2 v-pre>{{message}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {}
});
</script>
# 06 v-cloak
<div id ="app">
<h2 v-cloak>{{message}}</h2>
</div>
<script>
//在Vue解析之前,div中有一个属性v-cloak
//在vue解析之后,div中没有一个属性v-cloak
var app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {}
});
</script>
# 03 绑定属性
# 01 v-bind基本使用
<div id ="app">
<!-- 错误的做法,这里不可以使用mustache语法 -->
<!-- <img src="{{imgURL}}" alt=""> -->
<!-- 正确的做法:使用v-bind指令 -->
<img v-bind:src="imgURL" alt="">
<a v-bind:href="aHref">{{aMessage}}</a>
<!-- 语法糖的写法 -->
<img :src="imgURL" alt="">
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
imgURL: 'https://img20.360buyimg.com/babel/s590x470_jfs/t1/145861/20/3841/76376/5f1e3ca8Efa134bcf/ecce5b402f1274d0.jpg.webp',
aHref: 'http://www.baidu.com',
aMessage: '百度一下'
},
methods: {}
});
</script>
# 02 v-bind动态绑定class(对象语法)
<div id ="app">
<!-- <h2 class="active">{{message}}</h2>
<h2 :class="active">{{message}}</h2> -->
<!-- <h2 v-bind:class="{key1: value1, key2: value2}">{{message}}</h2> -->
<!-- <h2 v-bind:class="{类名: boolean, 类名2: boolean}">{{message}}</h2> -->
<h2 class="title" v-bind:class="{active: isActive, line: isLine}">{{message}}</h2>
<h2 class="title" v-bind:class="getClasses()">{{message}}</h2>
<button @click="btnClick()">按钮</button> //这里的btnClick方法可以省略()
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
active: 'active',
isActive: 'true',
isLine: 'false'
},
methods: {
btnClick: function (){
this.isActive = !this.isActive;
},
getClasses: function() {
return {active: this.isActive, line: this.isLine};
}
}
});
</script>
# 03 v-bind动态绑定class(数组语法)
<div id ="app">
<!-- 加单引号是字符串,不加单引号会作为变量解析 -->
<h2 class="title" :class="['active', 'line']">{{message}}</h2>
<h2 class="title" :class="getClasses()">{{message}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
active: 'aaaa',
line: 'bbbbbb'
},
methods: {
getClasses: function () {
return ['active', 'line'];
}
}
});
</script>
# 04 作业(v-for和v-bind结合)
<!-- 点击列表中的哪一项,哪一项就变成红色 -->
<div id ="app">
<ul>
<li :class="{active: isActive}" @click="insertClass()" v-for="(item,index) in movies">{{index}} - {{item}}</li>
</ul>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
movies: ['海王', '海尔兄弟', '火影忍者', '进击的巨人'],
isActive: true
},
methods: {
insertClass: function () {
}
}
});
</script>
# 05 v-bind动态绑定style(对象语法)
<div id ="app">
<!-- <h2 :style="{key(css属性名): value(属性值)}"></h2> -->
<!-- 注意这里50px要加引号,不加会当作变量,前面的key可以不用加,因为就是个key -->
<h2 :style="{fontSize: '50px'}">{{message}}</h2>
<!-- 这里是直接引用变量 -->
<h2 :style="{fontSize: finalSize}">{{message}}</h2>
<h2 :style="{fontSize: finalNum + 'px', color: finalColor}">{{message}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
finalSize: '100px',
finalNum: 100,
finalColor: 'red'
},
methods: {}
});
</script>
# 06 v-bind动态绑定style(数组语法)
<div id ="app">
<h2 :style="[baseStyle,baseStyle1]">{{message}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
baseStyle: {backgroundColor: 'red'},
baseStyle1: {fontSize: '100px'},
},
methods: {}
});
</script>
# 04 计算属性
# 01 计算属性的基本使用
<div id ="app">
<h2>{{firstName + ' ' + lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<h2>{{getFullName()}}</h2>
<h2>{{fullName}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
firstName: 'Lebron',
lastName: 'James'
},
methods: {
getFullName() {
return this.firstName + ' ' + this.lastName;
}
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName;
}
}
});
</script>
# 02 计算属性的复杂操作
<div id ="app">
<h2>总价格:{{totalPrice}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
books: [
{id: 110, name: 'Unix变成艺术', price: 119},
{id: 111, name: '代码大全', price: 105},
{id: 112, name: '深入立即计算机原理', price: 98},
{id: 113, name: '现代操作系统', price: 87},
]
},
computed: {
totalPrice: function () {
return this.books.reduce((total,book) => {
return total += book.price;
},0)
}
},
methods: {}
});
</script>
# 03 计算属性的setter和getter
<div id ="app">
<h2>{{firstName}}</h2>
<h2>{{lastName}}</h2>
<h2>{{fullName}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
firstName: 'kobe',
lastName: 'bryant'
},
computed: {
fullName: {
get() {
console.log('--调用了fullName的get');
return this.firstName + ' ' + this.lastName;
},
set(newValue) { //set不常用
console.log('---调用了fullName的set');
const name = newValue.split(' ');
this.firstName = name[0];
this.lastName = name[1];
}
}
},
methods: {}
});
</script>
# 04 计算属性的缓存
计算属性会进行缓存,如果多次使用时,计算属性只会调用一次。而methods是调用一次就会执行一次。
<div id ="app">
<h2>{{firstName}}</h2>
<h2>{{lastName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
firstName: 'kobe',
lastName: 'bryant'
},
computed: {
fullName: {
get() {
console.log('--调用了fullName的get');
return this.firstName + ' ' + this.lastName;
},
set(newValue) {
console.log('---调用了fullName的set');
const name = newValue.split(' ');
this.firstName = name[0];
this.lastName = name[1];
}
}
},
methods: {}
});
</script>
# 05 事件监听
# 01 v-on的基本使用
<div id ="app">
<h2>{{counter}}</h2>
<!-- <button v-on:click="increment">+</button>
<button v-on:click="decrement">-</button> -->
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
counter: 0
},
methods: {
increment(){
this.counter++;
},
decrement() {
this.counter--;
}
}
});
</script>
# 02 v-on的参数问题
<div id ="app">
<!--1.事件调用的方法没有参数 -->
<button @click="btn1Click()">按钮1</button>
<button @click="btn1Click">按钮1</button>
<!--2.在事件定义时,写方法时省略了小括号,但是方法本身是需要一个参数的,
这个时候,vue会默认将浏览器产生的event事件对象作为参数传入到方法。
如果写了括号,但是不传参数的话,函数会接收到undefined。
-->
<button @click="btn2Click">按钮2</button>
<button @click="btn2Click()">按钮2</button>
<button @click="btn2Click('abc')">按钮2</button>
<!--3.方法定义时,我们需要event对象,同时又需要其他参数
在调用时,如何手动的获取到浏览器参数的event对象:$event-->
<button @click="btn3Click('abc',$event)">按钮3</button>
<button @click="btn3Click('abc')">按钮3</button>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {
btn1Click() {
console.log('按钮被点击!');
},
btn2Click(event) {
console.log('-------', event);
},
btn3Click(par,event){
console.log('-------', par, event);
}
}
});
</script>
# 03 v-on的修饰符
<div id ="app">
<!-- 1. .stop阻止冒泡 -->
<div @click = "divClick">
<span @click.stop = "spanClick">冒泡测试</span>
</div>
<!-- 2. .prevent阻止默认事件 -->
<br>
<form action="baidu">
<input type="submit" value="提交" @click.prevent="formClick">
</form>
<!-- 3. .enter监听键盘某个按键 -->
<input type="text" @keyup.enter="keyUp">
<!-- 4. once只触发一次回调 -->
<button @click.once="btnOnce">按钮2</button>
<!-- 5. native监听组件根元素的原生事件-->
<!-- 监听<back-top/>组件的点击事件 -->
<back-top @click.native="backTopClick" ></back-top>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {
divClick() {
console.log('divClick');
},
spanClick() {
console.log('spanClick');
},
formClick() {
console.log('formClick');
},
keyUp() {
console.log('keyup');
},
btnOnce() {
console.log('btnOnce');
}
}
});
</script>
# 06 条件的判断
# 01 v-if的使用
<div id ="app">
<div v-if="state">
<div>内容</div>
<div>内容</div>
<div>内容</div>
</div>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
state: true
},
methods: {}
});
</script>
# 02 v-if和v-else的使用
<div id ="app">
<div v-if="state">
<span>v-if显示的内容</span>
</div>
<div v-else>v-else显示的内容</div>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
state: true
},
methods: {}
});
</script>
# 03 v-if和v-else-if和v-else的使用
<div id ="app">
<div v-if="score > 90">优秀</div>
<div v-else-if="score > 80">良好</div>
<div v-else-if="score > 60">及格</div>
<div v-else>不及格</div>
<div>{{level}}</div>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
score: 100
},
methods: {},
computed: {
level() {
let state = '优秀';
if(this.score > 90){
state = '优秀';
}else if(this.score > 90){
state = '良好';
}else if(this.score > 60) {
state = '及格';
}else{
state = '不及格';
}
return state;
}
}
});
</script>
# 04 用户登陆案例切换
<div id ="app">
<span v-if="isUser">
<label for="username">用户账号</label>
<input type="text" id="username" placeholder="用户账号">
</span>
<span v-else=>
<label for="email">用户邮箱</label>
<input type="text" id="email" placeholder="用户邮箱">
</span>
<button @click=" isUser = !isUser">切换类型</button>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
isUser: true
},
methods: {}
});
</script>
# 06 v-show的使用
<div id ="app">
<!--v-if: 当条件为false时, 包含v-if指令的元素, 根本就不会存在dom中-->
<h2 v-if="isShow">{{message}}</h2>
<!--v-show: 当条件为false时, v-show只是给我们的元素添加一个行内样式: display: none-->
<h2 v-show="isShow">{{message}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true
},
methods: {}
});
</script>
# 07 循环遍历
# 01 v-for循环遍历数组
<div id ="app">
<!-- 遍历数组,只拿到值 -->
<ul v-for="item in names">
<Li>{{item}}</Li>
</ul>
<!-- 遍历数组,拿到值和下标 -->
<ul v-for="(item,index) in names">
<Li>{{index}}.{{item}}</Li>
</ul>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
names: ['猪八戒', '孙悟空', '唐僧', '沙僧']
},
methods: {}
});
</script>
# 02 v-for循环遍历对象
<body>
<div id ="app">
<!-- 遍历对象,如果只获取一个值的话,只拿到value -->
<ul v-for="item in info">
<li>{{item}}</li>
</ul>
<!-- 遍历对象,如果获取两个值的话,参数:(value,key) -->
<ul v-for="(value,key) in info">
<li>{{key}}-{{value}}</li>
</ul>
<!-- 遍历对象,如果获取到三个值的话,参数(value,key,index) -->
<ul v-for="(value,key,index) in info">
<li>{{index+1}}.{{key}}-{{value}}</li>
</ul>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
info: {
name: 'chengyi',
age: 18,
height: 1.88
}
},
methods: {}
});
</script>
# 03 v-for使用过程添加key
这里使用key的原因是因为虚拟dom的原因,diff算法。
<div id ="app">
<ul>
<li v-for="item in letters" :key="item">{{item}}</li>
</ul>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
letters: ['a', 'b', 'c', 'd', 'e']
},
methods: {}
});
</script>
# 04 哪些数组的方法是响应式的
<div id ="app">
<ul>
<li v-for="item in letters">{{item}}</li>
</ul>
<button @click="btnClick">按钮</button>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
letters: ['a','c','b','d']
},
methods: {
btnClick() {
//1.push方法
// this.letters.push('aaa');
// this.letters.push('bbb','bbb','ccc');
//2.pop(): 删除数组中的最后一个元素
// this.letters.pop();
//3.shift(): 删除数组中的第一个元素
// this.letters.shift();
//4.unshift(): 在数组最前面添加元素
// this.letters.unshift('aaa','bbb');
//5.splice作用:删除元素/插入元素/替换元素
//删除元素:第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)
//替换元素:第二个参数,表示我们要替换几个元素,后面是用于替换前面的元素
//插入元素:第二个参数,传入0,并且后面跟上要插入的元素
//this.letters.splice(1,3,'m','n','l','x');
//5.sort()
// this.letters.sort();
//6.reverse()
// this.letters.reverse();
//注意:通过索引值修改数组中的元素
// this.letters[0] = 'bbbb'; //这种方法不会动态响应,因为vue没有添加这种方式
//通过以下两种方式修改
// this.letters.splice(0,1,'bbbb');
// set(要修改的对象,索引值,修改后的值)
Vue.set(this.letters, 0, 'bbb');
}
}
});
</script>
# 05 作业讲解
<div id ="app">
<ul>
<li v-for="(item,index) in movies" :class="{active: currentIndex === index}" @click="liClick(index)">{{item}}</li>
</ul>
</div>
<script>
//列表中,点击谁谁就变成唯一的红色
var app = new Vue({
el: '#app',
data: {
movies: ['海王', '海贼王', '加勒比海盗', '海尔兄弟'],
currentIndex: 0
},
methods: {
liClick(index) {
this.currentIndex = index;
}
}
});
</script>
# 08 书籍购物车案例
这里面使用了filters语法
<div id="app">
<div v-if="books.length">
<table>
<thead>
<tr>
<th></th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{item.price | showPrice}}</td>
<td>
<button @click="decrement(index)" v-bind:disabled="item.count <= 1">-</button>
{{item.count}}
<button @click="increment(index)">+</button>
</td>
<td><button @click="removeHandle(index)">移除</button></td>
</tr>
</tbody>
</table>
<h2>总价格: {{totalPrice | showPrice}}</h2>
</div>
<h2 v-else>购物车为空</h2>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
books: [
{
id: 1,
name: '《算法导论》',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '《UNIX编程艺术》',
date: '2006-2',
price: 59.00,
count: 1
},
{
id: 3,
name: '《编程珠玑》',
date: '2008-10',
price: 39.00,
count: 1
},
{
id: 4,
name: '《代码大全》',
date: '2006-3',
price: 128.00,
count: 1
},
]
},
methods: {
// getFinalPrice(price) {
// return '¥' + price.toFixed(2)
// }
increment(index) {
this.books[index].count++
},
decrement(index) {
this.books[index].count--
},
removeHandle(index) {
this.books.splice(index, 1)
}
},
computed: {
totalPrice() {
let totalPrice = 0
for (let i = 0; i < this.books.length; i++) {
totalPrice += this.books[i].price * this.books[i].count
}
return totalPrice
// for (let i in/of this.books)
// reduce
}
},
filters: {
showPrice(price) {
return '¥' + price.toFixed(2)
}
}
})
</script>
# 09 v-model的使用
# 01 v-model基本使用
v-model双向绑定
<div id ="app">
<input type="text" v-model="message">
{{message}}
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: 'hello world'
},
methods: {}
});
</script>
# 02 v-model的原理
<div id ="app">
<!-- <input type="text" :value="message" @input="changeInput">
{{message}} -->
<input type="text" :value='message' @input="message = $event.target.value">
{{message}}
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: 'hello world'
},
methods: {
changeInput(event) {
this.message = event.target.value;
}
}
});
</script>
# 03 v-model结合radio类型
<div id ="app">
<label for="male">
<input type="radio" id="male" value="男" name="sex" v-model="sex">男
</label>
<label for="female">
<input type="radio" id="female" value="女" name="sex" v-model="sex">女
</label>
<h2>您当前选中的是:{{sex}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
sex: '男'
},
methods: {}
});
</script>
# 04 v-model结合checkbox类型
<div id ="app">
<!-- 单选 -->
<!-- <label for="agree">
<input type="checkbox" name="" id="agree" v-model="isAgree">请同意协议
</label>
<h2>您的选择是:{{isAgree}}</h2>
<button :disabled="!isAgree">下一步</button> -->
<!-- 多选 -->
<input type="checkbox" name="" value="篮球" id="" v-model="hobbies">篮球
<input type="checkbox" name="" value="乒乓球" id="" v-model="hobbies">乒乓球
<input type="checkbox" name="" value="羽毛球" id="" v-model="hobbies">羽毛球
<input type="checkbox" name="" value="足球" id="" v-model="hobbies">足球
<h2>您的爱好是:{{hobbies}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
isAgree: false,
hobbies: []
},
methods: {}
});
</script>
# 05 v-model结合select类型
<div id ="app">
<!-- 1. 选择一个 -->
<select name="abc" id="" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="榴莲">榴莲</option>
<option value="橘子">橘子</option>
</select>
<h2>我选中的是: {{fruit}}</h2>
<!-- 2. 选择多个 -->
<select name="abc" id="" v-model="mySelect" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="榴莲">榴莲</option>
<option value="橘子">橘子</option>
</select>
<h2>我选中的是: {{mySelect}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
fruit: '苹果',
mySelect: []
},
methods: {}
});
</script>
# 06 v-model修饰符的使用
<div id ="app">
<!-- 1. lazy -->
<input type="text" name="" id="" v-model.lazy="message">
<h2>您输入的:{{message}}</h2>
<!-- 2. number -->
<input type="number" name="" id="" v-model.number="num">
<h2>{{num}}-{{typeof num}}</h2>
<!-- 3.修饰符 .trim -->
<input type="text" name="" id="" v-model.trim="blockString">
<h2>去重后的字符串:{{blockString}}</h2>
</div>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: 'hello world',
num: 0,
blockString: ''
},
methods: {}
});
</script>
# 10 组件化开发
# 01 组件化的基本使用
<div id ="app">
<!-- 3.使用组件 -->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script>
// 1.创建组件为构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈!</p>
<p>我是内容,呵呵呵! </p>
</div>
`
})
// 2.注册组件
Vue.component('my-cpn',cpnC);
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {}
});
</script>
# 02 全局组件和局部组件
<div id ="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<script>
// 1. 创建组件构造器
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈!</p>
<p>我是内容,呵呵呵! </p>
</div>
`
})
// 2. 注册组件
// Vue.component('cpn',cpnC);
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
// 局部组件
components: {
// cpn为使用组件时的标签名
cpn: cpnC
}
});
</script>
# 03 父组件和子组件
<div id ="app">
<cpn></cpn>
</div>
<script>
// 1.创建第一个组件
const cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容,呵呵</p>
</div>
`
})
// 2.创建第二个组件
const cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容,呵呵</p>
<cpn></cpn>
</div>
`,
// 将子组件挂载到父组件
components: {
cpn: cpnC1
}
})
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn: cpnC2
}
});
</script>
# 04 组件的语法糖注册方式
主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替
<div id ="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script>
// 1.全局组件注册的语法糖
// 1.创建组件构造器
// const cpnC = Vue.extend();
// 2.注册局部组件的语法糖
Vue.component('cpn1', {
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈!</p>
<p>我是内容,呵呵呵! </p>
</div>
`
})
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn2: {
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容,哈哈哈!</p>
<p>我是内容,呵呵呵! </p>
</div>
`
}
}
});
</script>
# 05 组件模版的分离写法
<div id ="app">
<cpn1></cpn1>
</div>
<!--1.script标签, 注意:类型必须是text/x-template-->
<!-- <script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
</div>
</script> -->
<!-- 2.template标签 -->
<template id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
</div>
</template>
<script>
// 1.注册一个全局组件
Vue.component('cpn1',{
template: '#cpn'
});
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {}
});
</script>
# 06 组件中数据的存放问题
data属性必须是一个函数 而且这个函数返回一个对象,对象内部保存着数据
<div id ="app">
<cpn></cpn>
</div>
<!-- 1. 创建了一个组件 -->
<template id="cpnC">
<div>
<h2>{{title}}</h2>
<p>我是内容,呵呵呵</p>
</div>
</template>
<script>
Vue.component('cpn', {
template: '#cpnC',
data() {
return {
title: '我是标题'
}
}
})
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {}
});
</script>
# 07 组件中的data为什么必须是函数
原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
<div id ="app">
<cpn></cpn>
</div>
<template id="cpnC">
<div>
<h2>当前计数:{{counter}}</h2>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script>
Vue.component('cpn', {
template: '#cpnC',
data() {
return {
counter: 0
}
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter--;
}
}
})
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {}
});
</script>
# 08 父组件向子组件传递数据
在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式:
- 方式一:字符串数组,数组中的字符串就是传递时的名称。
- 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
当我们有自定义构造函数时,验证也支持自定义的类型
<div id ="app">
<cpn v-bind:cmovies="movies" :cmessage="message"></cpn>
</div>
<template id="cpnC">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script>
const cpn = {
template: '#cpnC',
// props: ['cmovies', 'cmessage'],
data() {
return {
title: '模版父传子数据测试'
}
},
props: {
// 1.类型限制
// cmovies: Array,
// cmessage: String,
// 2.提供一些默认值, 以及必传值
cmessage: {
type: String,
default: '程意',
required: true
},
// 类型是对象或者数组时, 默认值必须是一个函数
cmovies: {
type: Array,
default() {
return []
}
}
}
}
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王','三十而立','二十不惑']
},
methods: {},
components: {
cpn
}
});
</script>
# 09 组件通信-父传子(props中的驼峰命名)
<div id ="app">
<!-- 使用-连接,组件中可使用驼峰命名接受到数据 -->
<cpn :c-info='info' :child-my-message="message"></cpn>
</div>
<template id="cpn">
<div>
<h2>{{cInfo}}</h2>
<h2>{{childMyMessage}}</h2>
</div>
</template>
<script>
const cpn = {
template: '#cpn',
props: {
cInfo: {
type: Object,
default() {
return {}
}
},
childMyMessage: {
type: String,
default: ''
}
}
}
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
info: {
age: '18',
name: '程意',
height: '1.88'
},
message: '你好啊'
},
methods: {},
components: {
cpn
}
});
</script>
# 10 组件通信-子传父自定义事件
<!-- 1.父组件模版 -->
<div id ="app">
<cpn @item-click="cpnClick"></cpn>
</div>
<!-- 2.子组件模版 -->
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script>
// 1. 子组件
const cpn = {
template: '#cpn',
data() {
return {
categories: [
{id: '1', name: '手机数码'},
{id: '2', name: '家用电器'},
{id: '3', name: '计生情趣'},
{id: '4', name: '男士服装'}
]
}
},
methods: {
// 发射事件: 自定义事件
btnClick(item) {
this.$emit("item-click",item)
}
}
}
// 2.父组件
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log("cpnClick",item);
}
}
});
</script>
# 11 组件通信-父子组件通信案例
题目要求:1.子组件的变量双向绑定。2.子组件变量的修改影响父组件的值。3.第一个变量是第二个变量的十分之一
<div id ="app">
<cpn :dnumber1='number1' :dnumber2='number2' @inputnumber1='inputnumber1' @inputnumber2='inputnumber2'></cpn>
</div>
<template id="cpn">
<div>
<h2>props: {{dnumber1}}</h2>
<h2>data: {{number1}}</h2>
<!-- <input type="text" v-model="number1"> -->
<input type="text" :value="number1" @input="inputNumber1">
<h2>props: {{dnumber2}}</h2>
<h2>data: {{number2}}</h2>
<!-- <input type="text" v-model="number2"> -->
<input type="text" :value="number2" @input="inputNumber2">
</div>
</template>
<script>
let cpn = {
template: '#cpn',
props: {
dnumber1: Number,
dnumber2: Number
},
data() {
return {
number1: this.dnumber1,
number2: this.dnumber2
}
},
methods: {
inputNumber1(event) {
// 1.将input中的value赋值到dnumber中
this.number1 = parseFloat(event.target.value);
// 2.为了让父组件可以修改值, 发出一个事件
this.$emit('inputnumber1', event.target.value);
// 3.同时修饰dnumber2的值
this.number2 = this.number1 * 100;
this.$emit('inputnumber2', this.number2);
},
inputNumber2(event) {
this.number2 = event.target.value;
this.$emit('inputnumber2', event.target.value);
// 同时修改dnumber2的值
this.number1 = this.number2 / 100;
this.$emit('inputnumber1', this.number1);
}
}
}
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
number1: 0,
number2: 1
},
methods: {
inputnumber1(value) {
this.number1 = parseFloat(value);
},
inputnumber2(value) {
this.number2 = parseFloat(value);
}
},
components: {
cpn
}
});
</script>
# 12 组件通信-父子组件通信案例(watch实现)
<div id="app">
<cpn :number1="num1"
:number2="num2"
@num1change="num1change"
@num2change="num2change"/>
</div>
<template id="cpn">
<div>
<h2>props:{{number1}}</h2>
<h2>data:{{dnumber1}}</h2>
<input type="text" v-model="dnumber1">
<h2>props:{{number2}}</h2>
<h2>data:{{dnumber2}}</h2>
<input type="text" v-model="dnumber2">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 0
},
methods: {
num1change(value) {
this.num1 = parseFloat(value)
},
num2change(value) {
this.num2 = parseFloat(value)
}
},
components: {
cpn: {
template: '#cpn',
props: {
number1: Number,
number2: Number,
name: ''
},
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2
}
},
watch: {
dnumber1(newValue) {
this.dnumber2 = newValue * 100;
this.$emit('num1change', newValue);
},
dnumber2(newValue) {
this.number1 = newValue / 100;
this.$emit('num2change', newValue);
}
}
}
}
})
</script>
# 13 组件反问-父访问子-children-refs
<div id ="app">
<cpn ref="aaa"></cpn>
<button @click="clickBtn">按钮</button>
</div>
<template id='cpn'>
<div>我是子组件</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {
clickBtn() {
// console.log(this.$children); //那到的是一个数组
// console.log(this.$children[0]); //拿到的是一个VueComponents对象
// console.log(this.$children[0].name); //我是子组件的name
console.log(this.$refs); //拿到的是一个键值对对象
console.log(this.$refs.aaa); //拿到组件ref属性为aaa的组件
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件的name'
}
},
methods: {
cpnClick() {
console.log('cpnclick');
}
}
}
}
});
</script>
# 14 组件访问-子访问父-parent-root
<div id ="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是cpn组件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是组件cpn'
}
},
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
console.log(this.$parent); //VueComponent
console.log(this.$parent.name); //我是组件cpn
console.log(this.$root); //Vue(直接拿到根组件)
}
}
}
}
}
}
});
</script>
# 11 组件化高级开发
# 01 slot-插槽的基本使用
<!--
1.插槽的基本使用 <slot></slot>
2.插槽的默认值 <slot>button</slot>
3.如果有多个值,同时放入到组件进行替换时,一起作为替换元素
-->
<div id ="app">
<cpn><button>按钮</button></cpn>
<cpn><span>哈哈哈</span></cpn>
<cpn>
<i>呵呵呵</i>
<div>我是div元素</div>
<p>我是p元素</p>
</cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>组件化开发</h2>
<p>我是组件内容</p>
<!-- <slot></slot> -->
<!-- 给插槽添加默认值 -->
<slot><button>按钮</button></slot>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn: {
template: '#cpn'
}
}
});
</script>
# 02 slot-具名插槽的使用
给插槽添加一个name属性
<div id ="app">
<!-- 2.在组件实例中添加slot属性,确定修改哪个插槽 -->
<cpn>
<span slot="center">标题</span>
<button slot="left">></button>
</cpn>
</div>
<!-- 1.给插槽添加name属性 -->
<template id="cpn">
<div>
<slot name="left">左边</slot>
<slot name="center">中间</slot>
<slot name="right">右边</slot>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn: {
template: '#cpn'
}
}
});
</script>
# 03 什么是编译的作用域
<div id ="app">
<!-- 这里起作用的app.isShow -->
<cpn v-show='isShow'></cpn>
</div>
<template id='cpn'>
<div>
<h2>我是子组件</h2>
<p>我是子组件的内容</p>
<!-- 这里起用的是组件的isShow -->
<button v-show="isShow">按钮</button>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {
isShow: true
},
methods: {},
components: {
cpn: {
template: '#cpn',
data() {
return {
isShow: false
}
}
}
}
});
</script>
# 04 作用域插槽的案例
父组件替换插槽的标签,但是内容由子组件来提供。
<div id ="app">
<cpn></cpn>
<cpn>
<!-- 2.通过slot-scope属性拿到组件的数据,新版本vue使用v-slot,而且不在需要template-->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item}} -</span> -->
<!-- 3.调用数据 -->
<span>{{slot.data.join('-')}}</span>
</template>
</cpn>
</div>
<template id='cpn'>
<div>
<!-- 1.将组件中的数组对外开放 -->
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
var app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguages: ['javascript','python','c++','Java','c#']
}
}
}
}
});
</script>
# 12 补充
# 01 时间总线
概念:因为组件就是Vue的一个实例,通过给Vue对象的prototype添加一个属性,属性值依然是一个Vue实例,然后就可以在所有组件中使用属性的$emit和$on。
创建时间总线
//在main.js当中 Vue.prototype.$bus = new Vue()
在组件当中使用总线的
$emit
发送事件this.$bus.$emit('goodsItemLoad');
在其他组件中监听事件总线发出的事件
created() { this.$bus.$on('goodsItemLoad', () => { console.log('成功监听到时间总线') }) }
# 02 防抖操作
防抖debounce/节流throttle(课下研究一下)
防抖函数起作用的过程:
- 如果我们直接执行refresh, 那么refresh函数会被执行30次.
- 可以将refresh函数传入到debounce函数中, 生成一个新的函数.
- 之后在调用非常频繁的时候, 就使用新生成的函数.
- 而新生成的函数, 并不会非常频繁的调用, 如果下一次执行来的非常快, 那么会将上一次取消掉
mounted() { const refresh = this.debounce(this.$refs.scroll.refresh, 300); this.$bus.$on('goodsItemLoad', () => { refresh(); }) }, methods: { debounce(func, delay) { let timer = null; return function(...args) { if(timer) clearTimeout(timer) timer = setTimeout(() => { func.apply(this, args) }, delay) } } }