组件 | 有怪兽
绑定变量
data函数,返回组件实例的data对象的函数,存放组件中需要使用的变量,所有变量写在return { } 中
在组件中html部分使用时通过{{}}解析,{{}}只能绑定元素的内容
{{}}中可以写:变量、访问数组元素、访问对象属性、算数计算、其它有返回值的表达式、三目运算符、有返回值的函数调用
data中保存的变量是响应式的,在 js 代码中修改变量值可马上更新到页面上
<template>
<div class="about">
{{ uname }}
</div>
</template>
<script>
export default {
data() {
return {
uname: "催三娘",
};
},
};
</script>
常用指令
v-text
绑定text文本,文本内容不会被解析,直接显示
v-html
绑定 html 片段,文本内容会被解析为 html
v-cloak
暂时隐藏页面内容的元素,编译结束才显示
v-cloak本身没有任何隐藏效果,单加v-cloak毫无作用
需要自定义 css 样式,用属性选择器找到所有带有v-cloak属性的元素,将他们隐藏
new Vue() 首次加载完之后,会自动找到页面上所有v-cloak属性,将他们删除
v-once
带有v-once的元素只在首次渲染页面内容时加载一次,之后及时变量值发生变化,也不会自动更新
v-pre
带有v-pre的元素内容中的{{}}会原样显示花括号里的内容,不会被解析
v-bind
绑定属性值
标准写法:<元素 v-bind:属性名="变量或表达式">
简写:可省略v-bind,<元素 :属性名="变量或表达式">
v-show
控制元素显示或隐藏
<元素 v-show="bool类型的变量或条件表达式">
如果变量值或表达式的值为 true ,则当前元素正常显示
如果变量值或表达式的值为 false ,则自动给当前元素加display:none,当前元素自动隐藏
v-if...v-else
控制元素显示或隐藏
<元素 v-if="bool类型的变量或条件表达式"> <元素 v-else >
两个元素必须紧邻,之间不允许有其他内容
如果v-if的条件为 true ,则显示v-if元素,删除v-else元素
如果v-if的条件为 false ,则删除v-if元素,显示v-else元素
可以使用 <元素 v-else-if="bool类型的变量或条件表达式"> </元素 >,进行多个元素控制
<template>
<div class="home">
{{ uname }}
<div v-text="h1"></div>
<div v-text="`${h1}`"></div>
<div v-html="h1"></div>
<div v-html="`${h1}`"></div>
<div v-pre>双花括号{{ h1 }} 不会解析</div>
<!-- 编译结束才显示,需要结合css使用 -->
<h1 v-cloak>用户名:{{ uname }}</h1>
<h1 v-once>我只加载一次:{{ str }}</h1>
<button @click="update">no</button>
<ul>
<li>Vue2</li>
<li v-bind:type="type">Vue3</li>
<li :type="type">TypeScript</li>
</ul>
<!-- 隐藏时不占用页面空间 -->
<div v-show="show">hello</div>
<!-- 绑定点击事件 -->
<button @click="isShow">isShow</button>
<br />
n:{{ n }}
<div v-if="n < 5">n小于5</div>
<div v-else-if="n > 5">n大于5</div>
<div v-else>n等于5</div>
<!-- 绑定点击事件 -->
<button @click="add">++</button>
</div>
</template>
<script>
export default {
data() {
return {
uname: "崔三娘",
h1: "<h1>hello</h1>",
str: "yes",
type: "none",
show: true,
n: 0,
};
},
methods: {
update() {
this.str = "no";
},
isShow() {
this.show = !this.show;
},
add() {
this.n++;
},
},
};
</script>
<style lang="scss" scoped>
[v-cloak] {
display: none;
}
</style>
v-for
循环生成元素
注意:v-for必须写在要反复生成的元素上,而不是父元素上
v-for可以遍历数组和对象,可以使用in和of,也可以遍历数字
为了给Vue一个提示,以便它跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key
遍历数组
- <要反复生成的元素 v-for="(数组元素,下标) of 数组" :key="下标">
- <要反复生成的元素 v-for="(数组元素,下标) in 数组" :key="下标">
遍历对象
- <要反复生成的元素 v-for="(对象属性值,对象属性, 索引) of 对象" :key="对象">
- <要反复生成的元素 v-for="(对象属性值,对象属性, 索引) in 对象" :key="对象">
遍历数字
可以循环数字,会从1开始数到数字为止
<template>
<div class="about">
<div v-for="(item, index) in arr">{{ item }}</div>
<hr />
<div v-for="(item, index) of arr">{{ item }}</div>
<hr />
<div v-for="(c, k, i) in obj">{{ c }},{{ k }},{{ i }}</div>
<hr />
<div v-for="(c, k, i) of obj">{{ c }},{{ k }},{{ i }}</div>
<hr />
<div v-for="item in 5">{{ item }}</div>
</div>
</template>
<script>
export default {
data() {
return {
arr: [1, 2, 3, 4],
obj: { a: 1, b: 2, c: 3, d: 4 },
};
},
};
</script>
Class 与 Style 绑定
class
vue中绑定class属性需要以对象形式绑定,对象的属性名为想绑定的class值,属性值为布尔类型
vue会把对象属性值为true的属性名,绑定到元素的class上,为false的不绑定
如元素还有单独的class属性会与:class绑定的属性合并到一起
<元素 :class="{ className : true/false }"> <元素>
<template>
<div class="about">
<!-- :class="{}" 对象中属性值为true的属性名,绑定到元素的class上 -->
<!-- 单独的class属性会与:class绑定的属性合并到一起 -->
<!-- colorX中colorRed为true,colorRed会被绑定到元素上,然后与class="w h"合并,最终为'wh colorRed' -->
<div class="wh" :class="colorX"></div>
<button @click="red">red</button>
<button @click="green">green</button>
</div>
</template>
<script>
export default {
data() {
return {
colorX: {
colorRed: true,
colorGreen: false,
},
};
},
methods: {
red() {
this.colorX.colorRed = true;
this.colorX.colorGreen = false;
},
green() {
this.colorX = {
colorRed: false,
colorGreen: true,
};
},
},
};
</script>
<style scoped>
.wh {
width: 100px;
height: 100px;
}
.colorRed {
background-color: red;
}
.colorGreen {
background-color: green;
}
</style>
Style
vue中绑定style属性需要以对象形式绑定
<元素 :style="{ 属性名: 属性值 }"> <元素>
-
对象的属性名为css属性名,原css中用原来用短横线命名法的属性要转换为小驼峰命名法
-
对象的属性值为css属性值,有单位的属性值必须加单位
<template>
<div class="about">
<div class="wh" :style="divStyle"></div>
<button @click="right">right</button>
<button @click="bottom">bottom</button>
<button @click="bgcolor">bgcolor</button>
</div>
</template>
<script>
export default {
data() {
return {
// 对象的属性名即css属性名,小驼峰命名法
divStyle: {
top: "100px",
left: "100px",
backgroundColor: "red",
},
};
},
methods: {
right() {
// 在原有属性值基础上 +5,原有属性值取出的都是字符串,需要装换
this.divStyle.left = parseInt(this.divStyle.left) + 5 + "px";
},
bottom() {
this.divStyle.top = parseInt(this.divStyle.top) + 5 + "px";
},
bgcolor() {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
this.divStyle.backgroundColor = `rgb(${r},${g},${b})`;
},
},
};
</script>
<style scoped>
.wh {
width: 100px;
height: 100px;
background-color: red;
position: fixed;
}
</style>
小总结
防止用户短暂看到{{}}
网页在加载中用户可能会暂时看到{{}}
解决办法:
- 在带有{{}}的元素上写v-cloak属性
- 用v-text指令代替{{}}绑定元素的内容
v-show 和 v-if区别
- v-show是通过添加display:none控制元素的显示隐藏,效率高
- v-if是通过删除元素的方式控制元素的显示隐藏,效率略低
data和methods
data
data函数,返回组件实例的data对象的函数,存放组件中需要使用的变量,所有变量写在return { } 中
data中的变量在组件中html部分使用时通过{{}}解析,在组件中js部分使用时通过this对象调用
<template>
<div class="about">
<!-- {{ }}使用变量 -->
n:{{ n }}
<!-- 通过指令使用变量 -->
<div v-text="n"></div>
<!-- 绑定点击事件 -->
<button @click="add">++</button>
</div>
</template>
<script>
export default {
data() {
return {
// 定义变量
n: 0,
};
},
methods: {
// 事件处理函数
add() {
// 通过this对象调用
this.n++;
},
},
};
</script>
methods
存放组件中需要使用的函数
methods中的函数在组件中html部分使用时通过函数名调用,在组件中js部分使用时通过this对象调用
<template>
<div class="about">
<!-- 通过{{ }}调用 -->
{{ getNum() }}
<!-- 通过指令调用 -->
<div v-text="getNum()"></div>
<div v-html="getNum()"></div>
<!-- 绑定点击事件 -->
<!-- 通过事件调用 -->
<button @click="toAdd">toAdd</button>
</div>
</template>
<script>
export default {
data() {
return {
num: 0,
};
},
methods: {
getNum() {
return this.num;
},
addNum() {
this.num++;
},
// 事件处理函数
toAdd() {
// 通过this对象调用
this.addNum();
},
},
};
</script>
注意,不应该使用箭头函数来定义method函数 (例如 add:() => this.num++),理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向组件实例,this.num将是 undefined。
修改数组
通过下标修改数组的元素内容,不能触发自动更新,数组内容已经改变,但无法响应到页面
<template>
<div class="about">
{{ citys }}
<br />
<button @click="update">update</button>
</div>
</template>
<script>
export default {
data() {
return {
citys: ["北京", "上海", "广州", "深圳"],
};
},
methods: {
update() {
this.citys[3] = "重庆";
console.log(this.citys);
},
},
};
</script>
解决办法:使用数组函数
<template>
<div class="about">
{{ citys }}
<br />
<button @click="update">update</button>
</div>
</template>
<script>
export default {
data() {
return {
citys: ["北京", "上海", "广州", "深圳"],
};
},
methods: {
update() {
this.citys.splice(3,1,'重庆');
}
},
};
</script>
事件绑定
我们可以使用 v-on 指令 (通常缩写为 @ 符号),来监听DOM事件,并在触发事件时执行一些JavaScript
标准写法:<元素 v-on:事件名="JavaScript">
简写:<元素 @事件名="JavaScript">
<template>
<div class="about">
n:{{ n }}
<br>
<!-- 绑定点击事件 -->
<button v-on:click="n++">v-on:click</button>
<button @click="n++">@click</button>
</div>
</template>
<script>
export default {
data() {
return {
n: 0,
};
},
};
</script>
事件处理函数
许多事件处理逻辑会更复杂,所以直接把JavaScript代码写在v-on指令中是不可行的,因此v-on还可以接收一个需要调用的方法名称
标准写法:<元素 v-on:事件名="事件处理函数">
简写:<元素 @事件名="事件处理函数">
<template>
<div class="about">
n:{{ n }}
<br>
<!-- 绑定点击事件 -->
<button v-on:click="add">v-on:click</button>
<button @click="add">@click</button>
</div>
</template>
<script>
export default {
data() {
return {
n: 0,
};
},
methods: {
// 事件处理函数
add() {
this.n++;
},
},
};
</script>
事件处理函数传参
<template>
<div class="about">
say:{{ msg }}
<br />
<!-- 绑定点击事件 -->
<button @click="say('bye')">bye</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: "hello",
};
},
methods: {
// 事件处理函数
say(str) {
this.msg = str;
},
},
};
</script>
$event
如需访问原始的DOM事件,可以用特殊变量$event,$event是vue定义好的变量,保存内容为js中的event事件对象
-
在调用函数时如果不传参,则默认会作为第一个参数传递进去
-
在调用函数时如果传参,则需要使用$event作为参数传递进去
<template>
<div class="about">
<!-- 绑定点击事件 -->
<button @click="fun">无参</button>
<button @click="fun1(0, $event)">带参</button>
</div>
</template>
<script>
export default {
methods: {
// 事件处理函数
fun($event) {
console.log($event);
},
fun1(a, $event) {
console.log($event);
},
},
};
</script>
多事件处理器
事件处理程序中可以有多个方法,这些方法由逗号运算符分隔
<template>
<div class="about">
<!-- 绑定点击事件,事件触发时调用两个函数 -->
<button @click="one(), two()">Submit</button>
</div>
</template>
<script>
export default {
methods: {
one() {
console.log("one");
},
two() {
console.log("two");
},
},
};
</script>
事件修饰符
.stop
阻止组件冒泡
<template>
<div class="about">
<div @click="say('hello')">
<!-- 事件冒泡 -->
<button @click="up()">hello</button>
say:{{ msg }}
</div>
<div @click="say('bye')">
<!-- 阻止冒泡 -->
<button @click.stop="up()">bye</button>
say:{{ msg }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
msg: "",
};
},
methods: {
say(str) {
this.msg = str;
},
up() {},
},
};
</script>
.prevent
阻止默认事件的发生
<template>
<div class="about">
msg:{{ msg }}
<form @submit="onSubmit">
<button>提交</button>
</form>
<form @submit.prevent="onSubmit">
<button>提交</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
msg: "未提交",
};
},
methods: {
onSubmit() {
this.msg = '已提交';
},
},
};
</script>
可以只使用修饰符
<!-- 只有修饰符 -->
<form @submit.prevent></form>
.capture
捕获冒泡。冒泡发生时,有该修饰符的dom元素会先触发事件,如果有多个,则由外到内依次执行,然后再按自然顺序执行触发的事件。
<template>
<div class="about">
<div @click.capture="one">
<div @click.capture="two">
<div @click.capture="three">
<div @click="up">
<button @click="btn">btn</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return { };
},
methods: {
btn() {
console.log("btn触发");
},
up() {
console.log("up触发");
},
one() {
console.log("one触发");
},
two() {
console.log("two触发");
},
three() {
console.log("three触发");
},
},
};
</script>
.self
只当在event.target是当前元素自身时触发处理函数
<template>
<div class="about">
<div class="one" @click.self="one">
<button @click="btn">btn</button>
</div>
</div>
</template>
<script>
export default {
data() {
return { };
},
methods: {
btn() {
console.log("btn触发");
},
one() {
console.log("one触发");
},
},
};
</script>
<style scoped>
.about .one {
height: 50px;
background-color: pink;
}
</style>
.once
事件只触发一次
<template>
<div class="about">
<button @click.once="btn">btn</button>
</div>
</template>
<script>
export default {
data() {
return {};
},
methods: {
btn() {
console.log("btn触发");
},
},
};
</script>
.native
监听子组件事件
<template>
<div class="component">
<h3>子组件</h3>
</div>
</template>
<script>
export default {};
</script>
<style scoped>
.component h3 {
background-color: pink;
}
</style>
<template>
<div class="about">
<my-component @click="btn"></my-component>
<my-component @click.native="btn"></my-component>
</div>
</template>
<script>
import MyComponent from "../components/MyComponent.vue";
export default {
components: { MyComponent },
data() {
return {};
},
methods: {
btn() {
console.log("btn触发");
},
},
};
</script>
.passive
事件的默认行为将会立即触发
比如:< div v-on:scroll.passive="onScroll" >...< /div >,我们在div上绑定了滚动事件,浏览器只有等内核线程执行到事件处理函数中代码的时候才会知道内部是否会调用preventDefault来阻止事件的默认行为,这个执行过程可能会造成页面卡顿。
.passive这个不阻止事件默认行为,直接在事件触发时告诉浏览器,我们在内部不会阻止事件的默认行为,提高执行速度。
双向绑定
- 单向绑定: 只能将程序中变量值的修改自动更新到页面上对应元素中,不能将页面上元素内容的变化自动更新回程序中的变量中
- 双向绑定: 既能将程序中变量值的修改自动更新到页面上对应元素中,又能将页面上元素内容的变化自动更新回程序中的变量中
v-model
<元素 v-model="变量">
v-model指令在表单< input />、< textarea >及< select >元素上创建双向数据绑定,它会根据控件类型自动选取正确的方法来更新元素
v-model在内部为不同的输入元素使用不同的property并抛出不同的事件:
- text和textarea元素使用value property和input事件
- radio和checkbox使用 checked property和change事件
- select字段将value作为prop并将change作为事件
input:text和textarea
<template>
<div class="about">
<!--
v-model=""变量的值会被绑定到input,textarea的value属性上,
oninput事件在元素值发生变化是立即触发,onchange在元素失去焦点时触发
-->
<input v-model="str1" @input="oni" @change="onc" />
<p>{{ str1 }}</p>
<textarea v-model="str2"></textarea>
<p>{{ str2 }}</p>
</div>
</template>
<script>
export default {
data() {
return {
str1: "",
str2: "",
};
},
methods: {
oni() {
console.log(`oni=>${this.str1}`);
},
onc() {
console.log(`onc=>${this.str1}`);
},
},
};
</script>
input:radio和input:checkbox和select
<template>
<div class="about">
<!-- radio和checkbox中v-model绑定的是checked属性的值,等同于 v-model:checked="" -->
<!--
vue会把v-model中变量的值跟value的值比较,相同的为选中状态,
v-model为双向绑定,当选项选中时,会把value的值赋值给v-model中的变量
-->
<label> <input type="radio" name="sex" value="1" v-model="sex" />男 </label>
<label> <input type="radio" name="sex" value="0" v-model="sex" />女 </label>
<h3>sex:{{ sex }}</h3>
<!-- 单个复选框,v-model=""绑定为布尔值,true为选中,false为未选中 -->
<label><input type="checkbox" v-model="isCheck" />同意</label>
<h3>isCheck:{{ isCheck }}</h3>
<!--
多个复选框,v-model=""绑定同一个数组,数组里的每个元素值会和每个选项的value值对比,相同的为选中,
v-model为双向绑定,当选项选中时,会把value的值添加到数组中,取消选中时,会把value的值从数组中移除
-->
<input type="checkbox" id="bj" value="sk" v-model="likes" />
<label for="sk">烧烤</label>
<input type="checkbox" id="sh" value="hg" v-model="likes" />
<label for="hg">火锅</label>
<input type="checkbox" id="gz" value="ky" v-model="likes" />
<label for="ky">烤鱼</label>
<h3>likes: {{ likes }}</h3>
<!--
单选下拉框,在select上绑定v-model="",vue会把v-model中变量的值跟选项的value值对比,相同的为选中状态,
v-model为双向绑定,当选项选中时,会把选项中的value的值赋值给v-model中的变量
-->
<select v-model="city">
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="gz">广州</option>
</select>
<h3>city: {{ city }}</h3>
<!--
多选下拉框,在select上绑定v-model="",绑定变量为数组,数组里的每个元素值会和每个选项的value值对比,相同的为选中,
v-model为双向绑定,当选项选中时,会把的value的值添加到数组中,取消选中时,会把value的值从数组中移除
-->
<select v-model="citys" multiple>
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="gz">广州</option>
<option value="sz">深圳</option>
</select>
<h3>citys: {{ citys }}</h3>
</div>
</template>
<script>
export default {
data() {
return {
sex: 1,
isCheck: false,
likes: [],
city: "sh",
citys: [],
};
},
};
</script>
侦听器
handler
监听data中一个变量的值的变化,只要变量的值发生改变,就自动执行监听函数
<template>
<div class="about">
<input type="text" v-model="uname" />
<br />
<input type="text" v-model="upwd" />
</div>
</template>
<script>
export default {
data() {
return {
uname: "",
upwd: "",
};
},
// 所有侦听器写在watch里
watch: {
// 函数名必须跟变量名一致,第一个参数为变量的新值,第二个参数为变量的旧值,参数可以不加
uname: function (newValue, oldValue) {
console.log(`uname变了=>旧值${oldValue},新值${newValue}`);
},
// 侦听器也可以写成对象形式
upwd: {
// 回调函数
handler(newValue, oldValue) {
console.log(`upwd变了=>旧值${oldValue},新值${newValue}`);
},
},
},
};
</script>
immediate
侦听器的immediate属性默认值为false,设置成true后,会在第一次绑定值的时候就执行回调函数
<template>
<div class="about">
<input type="text" v-model="uname" />
<br />
<input type="text" v-model="upwd" />
</div>
</template>
<script>
export default {
data() {
return {
uname: "",
upwd: "",
};
},
watch: {
uname: function (newValue, oldValue) {
console.log(`uname变了=>旧值${oldValue},新值${newValue}`);
},
upwd: {
handler(newValue, oldValue) {
console.log(`upwd变了=>旧值${oldValue},新值${newValue}`);
},
immediate: true,
},
},
};
</script>
deep
使用watch监听一个对象时,只能监听直接重新给对象赋值,对象里内部的变化的无法监听
deep可以深度监听对象内部变化,默认值为false不监听,true监听
<template>
<div class="about">
<input type="text" v-model="user.uname" />
<br />
<input type="text" v-model="user.upwd" />
</div>
</template>
<script>
export default {
data() {
return {
user: {
uname: "",
upwd: "",
},
};
},
methods: {},
watch: {
user: {
handler(newValue) {
console.log(`user变了=>${newValue.uname},${newValue.upwd}`);
},
immediate: false,
deep: true,
},
},
};
</script>
计算属性
保存一个函数的运行结果,可以在页面中以属性的方式调用
计算属性在第一次执行后,只有在函数中相关依赖发生改变的时候才会再次执行
基础方式
<template>
<div class="about">
<!-- 使用计算属性,使用时会调用函数,虽然是个函数,但是使用方式跟data的返回对象中的属性一样 -->
<h1>总价: ¥{{ total }}</h1>
<ul>
<li v-for="(p, i) of cart" :key="i">
{{ p.lname }} | ¥{{ p.price }} | {{ p.count }} | 小计: ¥{{
p.price * p.count
}}
<!-- 修改商品数量p.count -->
<button @click="add(i)">+</button>
</li>
</ul>
<!-- 使用了两次计算属性,但是函数只调用了次 -->
<h1>总价: ¥{{ total }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
cart: [
{ lid: 1, lname: "华为", price: 5599, count: 2 },
{ lid: 2, lname: "小米", price: 3399, count: 3 },
{ lid: 3, lname: "苹果", price: 8899, count: 1 },
],
};
},
methods: {
add(i) {
// 修改count中的值,由于计算属性中依赖cart,计算属性会重新执行
this.cart[i].count++;
},
},
// 所有计算属性写在computed里
computed: {
// 定义计算属性
total: function () {
console.log(`计算了一次总价`);
var sum = 0;
for (var p of this.cart) {
sum += p.price * p.count;
}
// 使用计算属性页面显示的就是返回值
return sum;
},
},
};
</script>
getter
<template>
<div class="about">
<h1>总价: ¥{{ total }}</h1>
<ul>
<li v-for="(p, i) of cart" :key="i">
{{ p.lname }} | ¥{{ p.price }} | {{ p.count }} | 小计: ¥{{
p.price * p.count
}}
<button @click="add(i)">+</button>
</li>
</ul>
<h1>总价: ¥{{ total }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
cart: [
{ lid: 1, lname: "华为", price: 5599, count: 2 },
{ lid: 2, lname: "小米", price: 3399, count: 3 },
{ lid: 3, lname: "苹果", price: 8899, count: 1 },
],
};
},
methods: {
add(i) {
this.cart[i].count++;
},
},
computed: {
// 定义计算属性
total: {
// 调用计算属性时会自动调用get方法,显示结果为返回值
get: function () {
console.log(`计算了一次总价`);
var sum = 0;
for (var p of this.cart) {
sum += p.price * p.count;
}
return sum;
},
},
},
};
</script>
计算属性与方法
在一个组件内使用多个相同的处理结果,计算属性函数只会执行一次。而方法(函数)会执行多次。
<template>
<div class="about">
<!-- 使用计算属性,使用时会调用函数,虽然是个函数,但是使用方式跟data的返回对象中的属性一样 -->
<h1>总价: ¥{{ total }}</h1>
<ul>
<li v-for="(p, i) of cart" :key="i">
{{ p.lname }} | ¥{{ p.price }} | {{ p.count }} | 小计: ¥{{
p.price * p.count
}}
<!-- 修改商品数量p.count -->
<button @click="add(i)">+</button>
</li>
</ul>
<!-- 使用了两次计算属性,但是函数只调用了次 -->
<h1>总价: ¥{{ total }}</h1>
<!-- 使用函数 -->
<h1>总价: ¥{{ getTotal() }}</h1>
<h1>总价: ¥{{ getTotal() }}</h1>
<h1>总价: ¥{{ getTotal() }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
cart: [
{ lid: 1, lname: "华为", price: 5599, count: 2 },
{ lid: 2, lname: "小米", price: 3399, count: 3 },
{ lid: 3, lname: "苹果", price: 8899, count: 1 },
],
};
},
methods: {
add(i) {
// 修改count中的值,由于计算属性中依赖cart,计算属性会重新执行
this.cart[i].count++;
},
getTotal() {
console.log(`getTotal计算了一次总价`);
var sum = 0;
for (var p of this.cart) {
sum += p.price * p.count;
}
// 使用计算属性页面显示的就是返回值
return sum;
},
},
// 所有计算属性写在computed里
computed: {
// 定义计算属性
total: function () {
console.log(`计算了一次总价`);
var sum = 0;
for (var p of this.cart) {
sum += p.price * p.count;
}
// 使用计算属性页面显示的就是返回值
return sum;
},
},
};
</script>
过滤器和自定义指令
过滤器 : 变量值操作,指令:元素DOM操作
过滤器
专门对变量的原始值进行加工,然后再显式的函数
变量会作为过滤器函数的第一个参数传进去
- <元素 :html属性="变量 | 过滤器"> { { 变量 | 过滤器 } } </元素>
- <元素 :html属性="变量 | 过滤器(参数1) "> { { 变量 | 过滤器(参数1) } } </元素>
- 多个过滤器可以连用 : { { 变量 | 过滤器1 | 过滤器2 | 过滤器3... } }
注意 : 如果这个过滤器之前可能有其它过滤器,则进入这个过滤器的值,已经不是变量的原始值,而是上一个过滤器的返回值
局部过滤器
只能在当前vue组件内调用
<template>
<div class="about">
<h3>{{ uname }}</h3>
<h3>{{ age }}</h3>
<!-- sex | gender: sex会做为gender函数的第一个参数传进去 -->
<h3 :title="sex | gender">{{ sex | gender }}</h3>
<!-- salary | format(5) : salary会做为format函数的第一个参数传进去,5会作为第二个参数传进去 -->
<h3 :title="salary | format(5)">{{ salary | format(5) }}</h3>
</div>
</template>
<script>
export default {
data() {
return {
uname: "zs",
age: 25,
sex: 1,
salary: 10000,
};
},
// 所有局部过滤器写在filters里
filters: {
// 定义过滤器
gender: function (value) {
return (value == 1 && "男") || (value == 0 && "女") || "未知";
},
format: function (value, n) {
return value.toFixed(n);
},
},
};
</script>
全局过滤器
在所有vue组件内都可以使用
1.在项目src下创建文件夹filter,在filter内创建文件filters.js
filter/filters.js
const filters = {
// 过滤器
gender: function (value) {
return (value == 1 && "男") || (value == 0 && "女") || "未知";
},
format: function (value, n) {
return value.toFixed(n);
},
}
export default filters;
2.在main.js内容引入过滤器
import filters from './filter/filters'
Object.keys(filters).forEach(key => {
// 绑定过滤器
Vue.filter(key, filters[key]);
});
3.在vue组件内使用方式与局部过滤器一样
<template>
<div class="about">
<h3>{{ uname }}</h3>
<h3>{{ age }}</h3>
<h3 :title="sex | gender">{{ sex | gender }}</h3>
<h3 :title="salary | format(5)">{{ salary | format(5) }}</h3>
</div>
</template>
<script>
export default {
data() {
return {
uname: "zs",
age: 25,
sex: 1,
salary: 10000,
};
},
};
</script>
自定义指令
<元素 v-指令名></元素>
定义指令时,指令名不要加v-前缀,使用时需要加v-前缀
当带有这个指令的DOM元素被渲染到页面上显示后,自动执行inserted()函数
因为inserted中通常都是执行原始的DOM操作,所以inserted函数的参数domElem自动获得当前带有指令的DOM元素
可以通过操作domElem参数,对带有当前指令的元素执行原始的DOM操作
1.在项目src下创建文件夹directive,在directive内创建文件directives.js
directive/directives.js
const directives = {
// 定义指令,指令名不要加v-
focus: {
inserted(domElem) {
domElem.focus();
}
},
}
export default directives;
2.在main.js内容引入指令
import directives from './directive/directives'
Object.keys(directives).forEach(key => {
// 绑定指令
Vue.directive(key, directives[key]);
});
3.在vue组件内使用指令
<template>
<div class="about">
<!-- 使用自定义指令, 注意加v- -->
<input type="text" v-focus />
</div>
</template>
父子组件
父子组件指组件之间的相对关系,并不是指固定的某些组件
创建子组件
在components创建MyCounter.vue
<template>
<div id="my-counter">
<button @click="minus">-</button>
<span>{{ n }}</span>
<button @click="add">+</button>
</div>
</template>
<script>
export default {
data() {
return {
n: 1,
};
},
methods: {
minus() {
this.n--;
this.n == 0 && (this.n = 1);
},
add() {
this.n++;
},
},
};
</script>
使用子组件
在About.vue中使用子组件
<template>
<div class="about">
<!-- 方式一 -->
<MyCounter />
<MyCounter />
<!-- 方式二: 组件名会被按照驼峰命名法解析,然后用-连接 -->
<my-counter />
<my-counter />
</div>
</template>
<script>
// 引入公共组件 @默认从src目录开始查找,文件后最.vue可以不加
import MyCounter from "../components/MyCounter.vue";
export default {
// 注册MyCounter组件
// 此处为语法糖写法,{属性名:属性值} => {MyCounter:MyCounter} => {MyCounter}
components: { MyCounter },
};
</script>
ref与$refs
ref 将元素或子组件的引用信息注册在父组件的$refs对象上
- 如果在普通的DOM元素上使用,绑定的就是DOM元素
- 如果用在子组件上,绑定的就是组件实例
$refs一个对象,包含所有通过ref绑定DOM元素和组件实例
<template>
<div class="component">
<h3>子组件</h3>
</div>
</template>
<template>
<div class="about">
<input type="text" ref="inp" />
<my-component ref="myc"></my-component>
<button @click="btn">btn</button>
</div>
</template>
<script>
import MyComponent from "../components/MyComponent.vue";
export default {
components: { MyComponent },
data() {
return {};
},
methods: {
btn() {
console.log(this.$refs);
},
},
};
</script>