Vue3基础语法
创建自己的Vscode代码片段
Mustache
语法
<div id="app"></div>
<template id="my-app">
<!-- 1.mustache的基本使用 -->
<!-- 可用“-”连接多个-->
<h2>{{message}} - {{message}}</h2>
<!-- 2.是一个js表达式 -->
<h2>{{counter * 10}}</h2>
<h2>{{message.split(' ').reverse().join(' ')}}</h2>
<!-- 3.也可以调用函数 -->
<h2>{{getReverseMessage()}}</h2>
<!-- 4.三元表达式-->
<h2>{{isShow ? '哈哈哈哈' : '呵呵呵呵'}}</h2>
<button @click="click">切换</button>
<!-- 错误用法 -->
<!-- ar name = "abc" -> 赋值语句,不是表达式 -->
<h2>{{var name = "abc"}}</h2>
<!-- if语句不是表达式,错误-->
<h2>{{ if (isShow) { return "哈哈哈" } }}</h2>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
message: "Hello World",
counter: 100,
isShow: true,
};
},
methods: {
getReverseMessage() {
return this.message.split(" ").reverse().join(" ");
},
click() {
this.isShow = !this.isShow;
},
},
};
Vue.createApp(App).mount("#app");
</script>
v-once
v-once
用于制定元素或者组件只渲染一次:
- 当数据发生变化时,元素或者组件以及所有的子元素将视为静态内容并且跳过;
- 该指令可以用于性能优化;
<h2>{{counter}}</h2>
<h2 v-once>{{counter}}</h2> // 只会被渲染一次,后续永不会改变
<button @click="increment">+1</button>
v-text
指令
用于更新元素的 textContent
:
<h2>{{message}}</h2>
<!-- 等价于下面代码,但上面更加灵活 -->
<h2 v-text="message"></h2>
v-html
默认情况下,如果我们展示的内容本身是 html 的,那么 vue 并不会对其进行特殊的解析。
若我们希望这个内容被vue解析,可使用v-html
。
<div id="app"></div>
<template id="my-app">
<div>{{msg}}</div>
<!--利用下面代码可实现html样式解析 -->
<div v-html="msg"></div>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
msg: "<span style='color:red; background: blue'>哈哈哈</span>",
};
},
};
Vue.createApp(App).mount("#app");
</script>
v-pre
v-pre
用于跳过元素和他的子元素的编译过程,显示原始的Mustache
标签:
跳过不需要编译的节点,加快编译的速度;
<template id="my-app">
<h2 v-pre>{{message}}</h2>
</template>
v-cloak
这个指令可以隐藏未编译的Mustache
标签直到组件实例准备完毕。
<template id="my-app">
<h2 v-cloak>{{message}}</h2>
</template>
v-bind
前端讲的一系列指令,主要是将值插入到模板内容中。
但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定。
- 比如动态绑定
a
元素的href
属性; - 比如动态绑定
img
元素的src
属性;
绑定属性我们使用v-bind
:
- 缩写::
- 预期:
any(with argument)|Object(without argument)
- 参数:
attrOrProp(optional)
- 修饰符:
- 用法:动态绑定一个或多个
ttribute
,或一个组件prop到表达式。
绑定class
介绍:
在开发中,有时候我们的元素class
也是动态的,比如:
- 当数据为某个状态时,字体显示红色。
- 当数据另一个状态时,字体显示黑色。
绑定class
有两种方式:
- 对象语法;
<div id="app"></div>
<template id="my-app">
<!-- 对象语法:{} 可以有多个键值对-->
<div :class="{active: isActive, title:isTitle}">哈哈哈哈</div>
<button @click="click">切换</button>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
isActive: false,
isTitle: true,
};
},
methods: {
click() {
this.isActive = !this.isActive;
this.isTitle = !this.isTitle;
},
},
};
Vue.createApp(App).mount("#app");
</script>
- 数组语法
<div id="app"></div>
<template id="my-app">
<!-- 数组语法:可以加三元运算符亦或者数组里可以嵌套对象-->
<div :class="['abc',{active: isActive, title:isTitle}]">哈哈哈哈</div>
<button @click="click">切换</button>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
isActive: false,
isTitle: true,
};
},
methods: {
click() {
this.isActive = !this.isActive;
this.isTitle = !this.isTitle;
},
},
};
Vue.createApp(App).mount("#app");
</script>
绑定style
介绍:
可以利用v-bind:style
来绑定一些CSS内联样式:
- 某些样式我们需要根据数据动态来决定;
- 如某些文字的颜色,大小等;
CSS property 名可以用驼峰式或短横线分隔来命名;
绑定class
有两种方式:
- 对象语法
<div id="app"></div>
<template id="my-app">
<div :style="{color: finalColor, fontSize: finalFontSize}">
哈哈哈哈哈
</div>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
finalColor: "red",
finalFontSize: "50px",
};
},
};
Vue.createApp(App).mount("#app");
</script>
- 数组语法
<div id="app"></div>
<template id="my-app">
<div :style="[style1Obj, style2Obj]">哈哈哈哈哈</div>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
style1Obj: {
color: "red",
fontSize: "30px",
},
style2Obj: {
textDecoration: "underline",
},
};
},
};
Vue.createApp(App).mount("#app");
</script>
动态绑定属性:
<div id="app"></div>
<template id="my-app">
<div :[name]="value">hhhhh</div>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
name: "abc",
value: "kobe",
};
},
};
Vue.createApp(App).mount("#app");
</script>
绑定一个对象:
如果我们希望将一个对象的所有属性,绑定到元素上的所有属性,可以直接使用v-bind
绑定一个对象;
<div id="app"></div>
<template id="my-app">
<div v-bind="info">哈哈哈哈哈</div>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
info: {
name: "why",
age: 18,
height: 1.88,
},
};
},
};
Vue.createApp(App).mount("#app");
</script>
v-on
绑定事件
v-on
的使用:
<div id="app"></div>
<template id="my-app">
<!-- 完整写法: v-on:监听的事件 -->
<button v-on:click="btn1click">按钮1</button>
<div class="area" v-on:mousemove="mouseMove">div</div>
<!-- 语法糖 -->
<button @click="btn1click">按钮1</button>
<!-- 绑定一个表达式 -->
<button @click="counter++">{{counter}}</button>
<!-- 绑定多个对象 -->
<div class="area" v-on="{click: btn1click, mousemove: mouseMove}">
div
</div>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
message: "Hello World",
counter: 100,
};
},
methods: {
btn1click() {
console.log("按钮1发生了点击");
},
mouseMove() {
console.log("鼠标移动");
},
},
};
Vue.createApp(App).mount("#app");
</script>
v-on
参数传递
<div id="app"></div>
<template id="my-app">
<!-- 默认传入event,可在方法中获取 -->
<button @click="btn1Click">按钮1</button>
<!-- $event可以获取到事件发生时的事件对象 -->
<button @click="btn2Click($event, 'coderwhy', 18)">按钮2</button>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
message: "Hello World",
};
},
methods: {
btn1Click(event) {
console.log(event);
},
btn2Click(event, name, age) {
console.log(name, age, event);
},
},
};
Vue.createApp(App).mount("#app");
</script>
v-on
的修饰符
v-on
支持修饰符,修饰符相当于对事件进行了一些特殊处理:
.stop
- 调用event.stopPropagation()
。.prevent
- 调用event.preventDefault()
。.capture
- 添加事件侦听器时使用Capture
模式。.self
- 只当事件是从侦听器绑定的元素本身触发时才触发回调。.{keyAlias}
- 仅当事件是从特定键触发时才触发回调。.once
- 只触发一次回调。.left
- 只当点击鼠标左键时触发。.left
- 只当点击鼠标右键时触发。.middle
- 只当点击鼠标中键时触发。.passive
-{passive: ture}
模式添加侦听器。
<div id="app"></div>
<template id="my-app">
<div @click="divClick">
<!-- 加上.stop可以阻止冒泡 -->
<button @click.stop="btnClick">按钮</button>
</div>
<!-- 指定触发监听事件的键盘文字 -->
<input type="text" @keydown.i="iKeyup" />
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
message: "Hello World",
};
},
methods: {
divClick() {
console.log("divClick");
},
btnClick() {
console.log("btnClick");
},
iKeyup() {
console.log("i");
},
},
};
Vue.createApp(App).mount("#app");
</script>
条件渲染
-
在某些情况下,我们需要根据当前的条件决定某些元素或组件是否渲染,这个时候我们就需要进行条件判断了。
-
Vue 提供了下面的指令来进行条件判断:
v-if
v-else
v-else-if
上述三种指令用于根据条件来渲染某一块的内容:
- 这些内容只有在条件为 true 时,才会被渲染出来;
- 这三个指令与JavaScript的条件语句 if、else、else if 类似;
<div id="app"></div>
<template id="my-app">
<input type="text" v-model="score" />
<h2 v-if="score > 90">优秀</h2>
<h2 v-else-if="score > 60">良好</h2>
<h2 v-else>不及格</h2>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
score: 90, // 分数默认为90;
};
},
};
Vue.createApp(App).mount("#app");
</script>
v-if 的渲染原理:
v-if
是惰性的;- 当条件为
false
时,其判断内容完全不会被渲染或者会被销毁; - 当条件为
true
时,才会真正渲染条件块中的内容;
v-if 和 template 结合使用可避免性能浪费
<div id="app"></div>
<template id="my-app">
<!-- 添加两个 div 虽然可以达到目的,但会造成性能的浪费 -->
<!-- <div v-if="isShowHa">
<h2>哈哈哈</h2>
<h2>哈哈哈</h2>
<h2>哈哈哈</h2>
</div>
<div v-else>
<h2>呵呵呵</h2>
<h2>呵呵呵</h2>
<h2>呵呵呵</h2>
</div> -->
<!-- 可利用 template 模板达到这种效果 -->
<template v-if="isShowHa">
<h2>哈哈哈</h2>
<h2>哈哈哈</h2>
<h2>哈哈哈</h2>
</template>
<template v-else>
<h2>呵呵呵</h2>
<h2>呵呵呵</h2>
<h2>呵呵呵</h2>
</template>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
isShowHa: true,
};
},
};
Vue.createApp(App).mount("#app");
</script>
- v-show
<div id="app"></div>
<template id="my-app">
<h2 v-show="isShow">哈哈哈哈</h2>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
isShow: true,
};
},
};
Vue.createApp(App).mount("#app");
</script>
v-show 和 v-if 的区别:
-
用法上的区别:
v-show
是不支持template
;v-show
不可以和v-else
一起使用;
-
本质的区别:
v-show
元素无论是否需要显示到浏览器上,它的 DOM 实际都是有渲染的,只是通过 CSS 的 display 属性来进行切换;v-if
当条件为 false 时,其对应的元素直接不会被渲染到 DOM 中;
-
开发中的选择
- 如果元素需要在显示和隐藏之间频繁切换,使用 v-show;
- 否则使用
v-if
;
列表渲染
v-for 的基本使用:
<div id="app"></div>
<template id="my-app">
<h2>电影列表</h2>
<ul>
<!-- 遍历数组 -->
<li v-for="(movie, index) in movies">{{index + 1}}.{{movie}}</li>
</ul>
<h2>个人信息</h2>
<ul>
<!-- 遍历对象 -->
<li v-for="(value, key, index) in info">
{{value}}-{{key}}-{{index + 1}}
</li>
</ul>
<!-- 遍历数字 -->
<ul>
<li v-for="(num, index) in 10">{{num}}-{{index}}</li>
</ul>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
movies: ["星际穿越", "盗梦空间", "大话西游", "教父"],
info: {
name: "why",
age: 18,
height: 1.88,
},
};
},
};
Vue.createApp(App).mount("#app");
</script>
v-for 和 template 结合使用:
<div id="app"></div>
<template id="my-app">
<ul>
<template v-for="(value, key) in info">
<li>{{value}}</li>
<li>{{key}}</li>
</template>
</ul>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
info: {
name: "why",
age: 18,
height: 1.88,
},
};
},
};
Vue.createApp(App).mount("#app");
</script>
数组更新检测和修改方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹的方法包括:
- push(): 添加元素
- pop(): 删除最后一个元素
- shift(): 删除第一个元素
- unshift(): 将一个或多个元素添加到数组开头
- splice(): 删除或替换现有元素或原地添加新的元素
- sort() : 对数组进行排序
- reverse(): 翻转数组
替换数组的方法
上面方法会直接修改运来的数组,但是某些方法不会替换原来的数组,而是会生成新的数组,比如 filter() (筛选数组)、concat() (合并两个或多个数组) 和 slice() (对原来数组的拷贝)。
<div id="app"></div>
<template id="my-app">
<ul>
<li v-for="(movie, index) in movies">{{index + 1}}.{{movie}}</li>
</ul>
<input type="text" v-model="newMovie" />
<button @click="addMovie">添加电影</button>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
newMovie: "",
movies: ["星际穿越", "盗梦空间", "大话西游", "教父", "默"],
};
},
methods: {
addMovie() {
this.movies.push(this.newMovie);
this.newMovie = "";
this.movies = this.movies.filter((item) => item.length > 2); // 将数组中字符长 度大于2的元素保留下来
},
},
};
Vue.createApp(App).mount("#app");
</script>
v-for 中 key 的作用
在使用 v-for
进行列表渲染时,我们通常会给元素或者组件绑定一个 key
属性。
具体作用为(官方解释):
key
属性主要作用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes;- 如果不适用
key
,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法; - 而使用
key
时,它会基于key
的变化重新排列元素顺序,并且会移除/销毁key
不存在的元素;
认识VNode (Virtual Node, 虚拟节点)
HTML元素 VNode 概念:
- 事实上,无论是组件还是元素,它们最终在 Vue 中表示出来的都是一个个
VNode
; VNode
的本质是一个JavaScript
对象;
<template>
<div class="title" style="font-size: 30px; color: red">哈哈哈</div>
</template>
// 模板中的代码产生的 VNode 如下
<script>
const vnode = {
type: "div",
props: { class: "title", style: { "font-size": "30px", color: "red" } },
children: "哈哈哈",
};
</script>
虚拟 DOM (VDom)
若存在的元素比较复杂,它们就会形成一个 VNode Tree,即为虚拟 DOM。
插入 f
案例
<div id="app"></div>
<template id="my-app">
<ul>
<li v-for="item of letters" :key="item">{{item}}</li> <!-- 使用 key 绑定,性能更高 -->
</ul>
<button @click="insertF">插入f元素</button>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
letters: ["a", "b", "c", "d"],
};
},
methods: {
insertF() {
this.letters.splice(2, 0, "f");
},
},
};
Vue.createApp(App).mount("#app");
</script>
\
复杂 data
的处理方式
-
在模板中可以直接通过插值语法显示一些
data
中的数据。 -
但在某些情况下,需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示;
- 需要对多个
data
数据进行运算、三元运算符来决定结果、数据进行某种转化后显示; - 在模板中使用表达式,可以非常方便的实现,但设计初衷是用于简单运算;
- 在模板中放入太多逻辑会让模板过重和难以维护;
- 如果很多地方都使用到,会有大量重复代码;
- 需要对多个
-
将逻辑抽离的方法:
- 将逻辑抽离到一个
method
中,放到methods
的options
中,但弊端是所有的data
使用过程都会变成方法的调用; - 使用计算属性
computed
;
- 将逻辑抽离到一个
认识计算属性 computed
计算属性的含义:
对于任何包含响应式数据的复杂逻辑,都应使用计算属性,它将被混入到组件实例中。所有 getter
和 setter
的 this
上下文自动地绑定为组件实例;
计算属性的用法:
- 选型:computed;
- 类型:{[key: string]: Function | {get: Function, set: Function}}
模板语法对案例的实现
<div id="app"></div>
<template id="my-app">
<h2>{{firstName + ' ' + lastName}}</h2>
<h2>{{score >= 60 ? '及格' : '不及格'}}</h2>
<h2>{{message.split(' ').reverse().join(' ')}}</h2>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
firstName: "Kobe",
lastName: "Bryant",
score: 80,
message: "Hello World",
};
},
};
Vue.createApp(App).mount("#app");
</script>
存在的缺点:
- 模板中存在大量复杂逻辑,不便于维护;
- 当有多次一样逻辑时,存在代码重复;
- 多次使用时,运算也需多次执行,没有缓存;
methods 方法对案例的实现
<div id="app"></div>
<template id="my-app">
<h2>{{getFullName()}}</h2>
<h2>{{getResult()}}</h2>
<h2>{{getReverseMessage()}}</h2>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
firstName: "Kobe",
lastName: "Bryant",
score: 80,
message: "Hello World",
};
},
methods: {
getFullName() {
return this.firstName + " " + this.lastName;
},
getResult() {
return this.score >= 60 ? "及格" : "不及格";
},
getReverseMessage() {
return this.message.split(" ").reverse().join(" ");
},
},
};
Vue.createApp(App).mount("#app");
</script>
存在的缺点:
- 显示调用结果不清晰,每次都是调用方法;
- 多次运算时,没有缓存;
计算属性 (computed) 对案例的实现
<div id="app"></div>
<template id="my-app">
<h2>{{fullName}}</h2>
<h2>{{result}}</h2>
<h2>{{reverseMessage}}</h2>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
firstName: "Kobe",
lastName: "Bryant",
score: 80,
message: "Hello World",
};
},
computed: {
// 定义了一个计算属性fullName
fullName() {
return this.firstName + " " + this.lastName; // 计算结果fullName会存入缓存中等待调用,不需要多次执行
},
result() {
return this.score >= 60 ? "及格" : "不及格";
},
reverseMessage() {
return this.message.split(" ").reverse().join(" ");
},
},
};
Vue.createApp(App).mount("#app");
</script>
特点:
- 计算属性看起来像一个函数,但在我们使用时不需要加 ''()'';
- 计算属性有缓存;
计算属性的 setter
和 getter
-
计算属性在大多数情况下,只需要一个
getter
方法即可,所以我们会将计算属性直接写成一个函数。 -
设置计算属性的值:
- 可以给计算属性设置一个
setter
方法;
- 可以给计算属性设置一个
认识侦听器 watch
侦听器的用法:
- 选项:watch
- 类型:{[key: string]: string | Function | Object | Array}
侦听器的意义:
- 在
data
返回的对象中定义数据,通过插值语法等方式绑定到template
中; - 当数据变化时,
template
会自动进行更新来显示最新的数据; - 某些情况下,我们希望在代码逻辑中监听某个数据的变化,需要使用侦听器
watch
来完成;
<div id="app"></div>
<template id="my-app">
您的问题: <input type="text" v-model="question" />
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
// 侦听到question的变化时,进行一些逻辑的处理
question: "Hello World",
};
},
watch: {
// question侦听的data中的属性的名称
// newValue变化后的新值
// oldValue变化前的旧值
question(newValue, oldValue) {
console.log("新值:", newValue, "旧值:", oldValue);
this.queryAnswer();
},
},
methods: {
queryAnswer() {
console.log(`你的问题${this.question}的答案是哈哈哈`);
},
},
};
Vue.createApp(App).mount("#app");
</script>
侦听器的配置选项
<div id="app"></div>
<template id="my-app">
<h2>{{info.name}}</h2>
<!-- <button @click="changeInfo">改变info</button> -->
<button @click="changeInfoName">改变info.name</button>
<button @click="changeInfoNbaName">改变info.nba.name</button>
</template>
<script src="../js/Vue.js"></script>
<script>
const App = {
template: "#my-app",
data() {
return {
info: { name: "why", age: 18, nba: { name: "kobe" } },
};
},
watch: {
// 默认情况下我们的侦听器只会针对侦听的数据本身的改变(内部发生的改变是不能侦听的)
// info(newInfo, oldInfo) {
// console.log('newValue:', newInfo,'oldValue:', oldInfo);
// }
// 深度侦听/立即执行(一定会执行一次)
info: {
handler: function (newInfo, oldInfo) {
console.log("newValue:", newInfo, "oldValue:", oldInfo);
},
deep: true, // 深度侦听
immediate: true, // 立即执行
},
},
methods: {
// changeInfo() {
// this.info = { name: "kobe" };
// },
changeInfoName() {
this.info.name = "kobe";
},
changeInfoNbaName() {
this.info.nba.name = "james";
},
},
};
Vue.createApp(App).mount("#app");
</script>
综合案例(书籍购物车)
HTML 部分
<body>
<div id="app"></div>
<template id="my-app">
<template v-if="books.length > 0">
<table>
<thead>
<th>序号</th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</thead>
<tbody>
<tr v-for="(book, index) of books">
<td>{{index + 1}}</td>
<td>{{book.name}}</td>
<td>{{book.date}}</td>
<td>{{formatPrice(book.price)}}</td>
<td>
<button :disabled="book.count <= 1" @click="decrement(index)">
-1
</button>
<span class="counter">{{book.count}}</span>
<button @click="increment(index)">+1</button>
</td>
<td><button @click="removeBook(index)">移除</button></td>
</tr>
</tbody>
</table>
<h2>总价格: {{formatPrice(totalPrice)}}</h2>
</template>
<template v-else>
<h2>购物车为空</h2>
</template>
</template>
<script src="../js/Vue.js"></script>
<script src="index.js"></script>
</body>
CSS 部分
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th,
td {
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}
.counter {
margin: 0 5px;
}
JS 部分
const App = {
template: "#my-app",
data() {
return {
books: [
{
id: 1,
name: "《算法导论》",
date: "2006-9",
price: 85.0,
count: 1,
},
{
id: 2,
name: "《UNIX编程艺术》",
date: "2006-2",
price: 59.0,
count: 1,
},
{
id: 3,
name: "《编程珠玑》",
date: "2008-10",
price: 39.0,
count: 1,
},
{
id: 4,
name: "《代码大全》",
date: "2006-3",
price: 128.0,
count: 1,
},
],
};
},
computed: {
totalPrice() {
let finalPrice = 0;
for (let book of this.books) {
finalPrice += book.count * book.price;
}
return finalPrice;
},
// Vue3不支持过滤器了,推荐两种方法: 使用计算属性/使用全局的方法
// 计算属性方法如下:
// filterBooks() {
// return this.books.map((item) => {
// item.price = "¥" + item.price;
// return item;
// });
// },
},
methods: {
increment(index) {
// 通过索引值获取到对象
this.books[index].count++;
},
decrement(index) {
this.books[index].count--;
},
removeBook(index) {
this.books.splice(index, 1);
},
formatPrice(price) {
return "¥" + price;
},
},
};
Vue.createApp(App).mount("#app");
\