文章目录
1. Vue初识
1.1 初学编写hello world和Counter
1.1.1 hello world
在页面中引入Vue。
<script src="https://unpkg.com/vue@next"></script>
引入CDN之后,就可以编写Vue的代码。
Vue3.0中,使用Vue.createApp()
来创建一个Vue的实例。
mount()
函数代表在指定的元素上使用Vue。
template是一个模板,里面存放要展示的内容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hello world</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
<script>
Vue.createApp({
template: "<div>hello world!</div>",
}).mount("#root");
</script>
</body>
</html>
这段代码的意思是,找到id为root的元素,把template模板放到这个元素中。
<div id="root"></div>
<script>
Vue.createApp({
template: "<div>hello world!</div>",
}).mount("#root");
这就是使用Vue写hello world的最简单的一个demo。
1.1.2 counter
同样要使用Vue.createApp
构建Vue实例。这次往模板中添加变量。要用两个花括号进行包裹{{}}
,代表一个JS表达式。
其中的变量要写在Vue.createApp
的data()
函数中。
data()
这个函数返回一个对象,对象的内容就是Vue实例要用到的变量。
Vue.createApp({
data() {
return {
content: 1,
};
},
template: "<div>{{content}}</div>",
}).mount("#root");
完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hello world</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
<script>
Vue.createApp({
data() {
return {
content: 1,
};
},
template: "<div>{{content}}</div>",
}).mount("#root");
</script>
</body>
</html>
这里引入一个mounted()
函数
mounted()
函数在页面加载完成后会自动执行。
改变数据,页面的内容就会跟着变。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hello world</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
<script>
Vue.createApp({
data() {
return {
content: 1,
};
},
// 页面加载完成执行mounted函数
mounted() {
setInterval(() => {
// this.$data.content 的简写
this.content += 1;
}, 1000);
},
template: "<div>{{content}}</div>",
}).mount("#root");
</script>
</body>
</html>
小结:Vue——面向数据编程。
1.2 编写字符串反转和内容隐藏小功能
1.2.1 字符串反转(v-on指令)
现在,我们让content中的内容变为字符串"hello world"
,并把这个字符串写到模板中,然后把模板挂载到id为root的元素上去。
Vue.createApp({
data() {
return {
content: "hello world",
};
},
template: "<div>{{content}}</div>",
}).mount("#root");
我们想在页面上新增一个按钮。写到template中去。
Vue.createApp({
data() {
return {
content: "hello world",
};
},
template: `
<div>{{content}}</div>
<button>反转</button>
`,
}).mount("#root");
给这个按钮绑定一个事件,要使用Vue的v-on
指令。对应的函数要写在methods中。
Vue.createApp({
data() {
return {
content: "hello world",
};
},
methods: {
handleBtnClick() {
console.log("hello world");
},
},
template: `
<div>{{content}}</div>
<button v-on:click="handleBtnClick">反转</button>
`,
}).mount("#root");
现在来编写handleBtnClick()
这个函数。
我们的目的是反转content的内容。
methods: {
handleBtnClick() {
this.content = this.content.split("").reverse().join("");
},
},
1.2.2 内容隐藏(v-if指令)
使用v-if可以控制某一元素是否要渲染在页面上。
Vue.createApp({
data() {
return {
show: true,
content: "hello world",
};
},
methods: {
handleBtnClick() {
this.show = this.show ? false : true;
},
},
template: `
<div v-if="show">{{content}}</div>
<button v-on:click="handleBtnClick">显示/隐藏</button>
`,
}).mount("#root");
1.3 编写TodoList小功能,了解循环和双向绑定(v-for指令、v-model指令)
1.3.1 v-for指令
现在,我们有一个数组,我们想让数组中的内容能够循环展示到页面上。
Vue.createApp({
data() {
return {
list: ["hello", "world", "cyy"],
};
},
}).mount("#root");
想要把数组中的内容循环展示,需要使用v-for
这个命令。
Vue.createApp({
data() {
return {
list: ["hello", "world", "cyy"],
};
},
methods: {},
template: `
<ul>
<li v-for="item of list">{{item}}</li>
</ul>
`,
}).mount("#root");
item指向list中的每一项。
v-for
指令中除了传入item
,还可以传入index
,比如这样:
Vue.createApp({
data() {
return {
list: ["hello", "world", "cyy"],
};
},
methods: {},
template: `
<ul>
<li v-for="(item, index) of list">{{item}}{{index}}</li>
</ul>
`,
}).mount("#root");
list
中的每一项放在item
中,每一项的下标放在index
中。
1.3.2 实现TodoList
新增input框,在点击按钮时,把input框中的内容添加到list中,并渲染到页面上进行显示。
想要获取Input框的内容,要使用v-model
指令进行双向绑定。
v-model="inputValue"代表当前输入框中的值和inputValue
的值是双向绑定在一起的。
Vue.createApp({
data() {
return {
list: [],
inputValue: "",
};
},
methods: {
handleAddItem() {
this.list.push(this.inputValue);
this.inputValue = "";
},
},
template: `
<div>
<input v-model="inputValue"/>
<button v-on:click="handleAddItem">增加</button>
<ul>
<li v-for="(item, index) of list">{{item}}{{index}}</li>
</ul>
</div>
`,
}).mount("#root");
1.4 组件概念初探,对TodoList进行组件代码拆分(v-bind指令)
1.4.1 v-bind指令
一个场景:
- 以前我们在标签中想使用一个数据,可以使用两个花括号
{{}}
这样的语法(插值表达式)比如:<button>{{item}}</button>
- 如果是想给标签上的某个属性进行数据的绑定,就不能使用插值表达式,要使用
v-bind
指令。比如<button v-bind:title="item"></button>
⭐v-bind指令:在标签上给某个属性绑定值。在标签内部绑定数据直接使用插值表达式即可。
1.4.2 组件的概念
组件就是页面上的一部分。
现在把TodoList的列表拆分成组件。
首先,把创建的Vue实例赋值给一个变量app
。
const app = Vue.createApp({
data() {
return {
list: [],
inputValue: "",
};
},
methods: {
handleAddItem() {
this.list.push(this.inputValue);
this.inputValue = "";
},
handleItemDelete(index) {
this.list.splice(index, 1);
},
},
template: `
<div>
<input v-model="inputValue"/>
<button v-on:click="handleAddItem" v-bind:title="inputValue">增加</button>
<ul>
<li v-for="(item, index) of list" v-on:click="handleItemDelete(index)">{{item}}</li>
</ul>
</div>
`,
});
之所以把Vue实例放到这个app中,是因为我们想要在这个名为app的实例中注册一些组件。
通过component()方法来注册组件。使用方法:Vue实例.component('组件名称', {})
,其中第二个参数是一个对象,用来描述这个组件中的内容。比如:
app.component("todo-item", {
template: `<div>hello world</div>`,
});
然后就可以在Vue的实例中使用<todo-item>
这个标签来添加这个组件。
最后要把app
这个Vue实例挂载到页面的DOM元素上。
<div id="root"></div>
<script>
const app = Vue.createApp({
data() {
return {
list: [],
inputValue: "",
};
},
methods: {
handleAddItem() {
this.list.push(this.inputValue);
this.inputValue = "";
},
handleItemDelete(index) {
this.list.splice(index, 1);
},
},
template: `
<div>
<input v-model="inputValue"/>
<button v-on:click="handleAddItem" v-bind:title="inputValue">增加</button>
<ul>
<todo-item v-for="(item, index) of list" v-on:click="handleItemDelete(index)">{{item}}</todo-item>
</ul>
</div>
`,
});
app.component("todo-item", {
template: `<div>hello world</div>`,
});
app.mount("#root");
一个组件应该包含该组件对应的展示内容(即DOM结构)、样式、JS逻辑。
正常情况下,一个组件中要包含要渲染的数据。
app.component("todo-item", {
data() {
return {
content: "hello",
};
},
template: `<div>{{content}}</div>`,
});
但是现在,我们把这个列表展示组件拆分了出去,变成了一个小的组件。这个组件中要展示的数据来自app
实例中的list
这个数组。
要把list的数据传递给这个小的组件,要在app
实例中,使用这个组件的地方,使用v-bind
把对应的数据绑定在标签上。这样,这个小组件todo-item
就能够感应到这个组件。
// app实例中
template: `
<div>
<input v-model="inputValue"/>
<button v-on:click="handleAddItem" v-bind:title="inputValue">增加</button>
<ul>
<todo-item v-for="(item, index) of list" v-bind:content="item" />
</ul>
</div>
`,
在todo-item
中,不需要再使用data()
方法来定义自己的函数,要使用props
来接受父组件传递过来的值。
// todo-item组件:
app.component("todo-item", {
props: ["content"],
template: `<div>{{content}}</div>`,
});
2. Vue.js基础语法、生命周期与事件
2.1 Vue中应用和组件的基础概念(mvvm设计模式)
2.1.1 引入mvvm
来看一个最基础的Vue实例。
const app = Vue.createApp({});
app.mount("#root");
解释一下这两句话是什么意思。
Vue.createApp({})
:创建一个Vue的应用。
app.mount("#root")
:这个名为app的应用只作用于id为root的DOM结点上。
再来丰富一下代码:
// 创建一个 Vue 应用,存储到 app 变量中
// 传入的参数表示,这个应用最外层的组件应该如何展示
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
template: `<div>{{content}}</div>`,
});
app.mount("#root");
在使用Vue.createApp
创建Vue实例时,我们为其中传入了参数。传入的参数表示,这个应用的最外层组件,应该如何展示。
现在,在创建应用之后,如果想获取对应创建的根组件,该如何获取?
其实,当我们调用app.mount()
方法的时候,它的返回值就是对应的根组件。
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
template: `<div>{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
当我们理解了应用和根组件之后,我们再来做一波分析。
实际上,我们已经感知到,Vue的编程是一种面向数据的编程。
我们定义了数据和模板,Vue会自动把数据和模板关联起来,变成我们想要展示的页面效果。
实际上,Vue这种面向数据的编程模式,是参考了mvvm这种设计模式。
⭐什么是mvvm?
m:model,数据
v:view,视图
vm:view Model,视图数据连接层
结合上面的例子来看,我们定义了数据+模板。数据对应的就是m(model,数据),模板对应的就是v(view,视图)。模板和数据会自动做连接,实际上这一层就是vm(view model,视图数据连接层)。
数据是我们自己写代码定义的,模板也是我们自己写代码定义的,但是数据和视图进行关联,并不是我们自己去做的,而是Vue帮助我们做的。更具体地讲,是Vue的组件帮助我们做的。
这就是为什么把const vm = app.mount("#root");
这句代码的返回值取名为vm的原因。
以后我们谈论到vm的时候,指的就是Vue的一个一个的组件。
2.1.2 vm的作用
我们说,数据和视图的关联是由vm来维护的,那么我们就可以借助vm来搞一些事情。
在vm上面,我们可以通过$data
的方式获取到对应根组件上面的数据。
比如对于这段代码:
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
template: `<div>{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
我们可以使用下面这行代码获取到content
的内容:
vm.$data.content // 'hello world'
也可以修改根组件的数据:
vm.$data.content = 'bye';
这样修改了数据,页面对应的数据也会随之发生变化。
2.1.3 本节小结
- 通过
const app = Vue.createApp()
可以创建一个Vue的应用。传递进去的参数表示的是,这个应用的根组件应该如何被创建。 const vm = app.mount()
方法返回的是Vue应用对应的根组件。这个根组件充当了一个vm层的角色- mvvm设计模式:m数据,v视图,vm数据视图连接层。
- 使用
vm
可以搞事情。vm.$data
可以获取到组件中的数据。
2.2 理解 Vue 中的生命周期函数(1)
先下定义:生命周期函数是在某一时刻会自动执行的函数。
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
// 在实例生成之前自动执行
beforeCreate() {
console.log("beforeCreate");
},
// 在实例生成之后自动执行
created() {
console.log("created");
},
// 将template变成render函数之后执行
// 在组件内容被渲染到页面之前自动执行
beforeMount() {
console.log("beforeMount");
},
// 在组件内容被渲染到页面之后自动执行
mounted() {
console.log("mounted");
},
template: `<div>{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.3 理解 Vue 中的生命周期函数(2)
使用app.unmount()可以使Vue应用失效(从页面卸载,销毁Vue实例)。
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
// 在实例生成之前自动执行
beforeCreate() {
console.log("beforeCreate");
},
// 在实例生成之后自动执行
created() {
console.log("created");
},
// 将template变成render函数之后执行
// 在组件内容被渲染到页面之前自动执行
beforeMount() {
console.log("beforeMount");
},
// 在组件内容被渲染到页面之后自动执行
mounted() {
console.log("mounted");
},
// 当data中的数据发生变化时自动执行
beforeUpdate() {
console.log("beforUpdate");
},
// 当data中的数据发生变化,页面重新渲染后,自动执行的函数
updated() {
console.log("updated");
},
// 当Vue应用失效时,自动执行的函数
beforeUnmount() {
console.log("beforeUnmount");
},
// 当Vue应用失效时,且dom完全销毁之后,自动执行的函数
unmounted() {
console.log("unmounted");
},
template: `<div>{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.4 常用模板语法讲解(1)
2.4.1 v-html指令
如果数据是一个html代码片段,不能直接使用插值表达式,否则Vue会将数据原样输出。
const app = Vue.createApp({
data() {
return {
content: "<h1>Hello World</h1>",
};
},
template: `<div>{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
页面显示:
如果想页面能把HTML标签解析成对应的节点,要使用v-html
指令
const app = Vue.createApp({
data() {
return {
content: "<h1>Hello World</h1>",
};
},
template: `<div v-html="content"></div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这样html标签就不会被转义。
2.4.2 v-bind指令
给标签的属性绑定数据。如果某个标签的属性值想使用数据变量,就要用v-bind
指令
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
template: `<div v-bind:title="content">{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
再举一个例子:
const app = Vue.createApp({
data() {
return {
disable: true,
};
},
template: `<input v-bind:disabled="disable"/>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.4.3 v-once指令
如果data发生改变,但不想让页面的内容跟着改变,就可以使用v-once
指令。表示这个标签中的内容只会渲染一次。
这个指令可以减少无用的渲染,提高渲染的性能。
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
template: `<div v-once>{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.4.5 v-if指令
控制页面是否渲染对应标签。
const app = Vue.createApp({
data() {
return {
content: "hello world",
show: false,
};
},
template: `<div v-if="show">{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.5 常用模板语法讲解(2)
2.5.1 v-on指令
用来绑定事件。
在模板上绑定的方法一定要卸载methods
对象中。
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
methods: {
handleBtnClick() {
alert("按钮被点击了");
},
},
template: `<button v-on:click="handleBtnClick">一个按钮</button>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.5.2 v-on、v-bind指令的缩写
v-on
指令可以缩写为一个@
,比如
template: `<button v-on:click="handleBtnClick">一个按钮</button>`
等价于
template: `<button @click="handleBtnClick">一个按钮</button>`
v-bind
指令可以直接简写为一个:
,比如:
template: `<button v-bind:title="content">一个按钮</button>`
等价于
template: `<button :title="content">一个按钮</button>`
2.5.3 自定义属性名
当template的元素上绑定的元素名称不固定,可以使用方括号语法来绑定一个变量,比如:
const app = Vue.createApp({
data() {
return {
content: "hello world",
name: "title",
};
},
methods: {
handleBtnClick() {
alert("按钮被点击了");
},
},
template: `<button :[name]="content">一个按钮</button>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这里还是给button元素的title属性绑定了content作为值。
2.5.4 阻止默认事件 .prevent修饰符
修饰符可以帮助我们简化一些常用代码的编写。Vue事件修饰符官网文档
定义一个表单,点击提交,跳转到百度。
const app = Vue.createApp({
data() {
return {
content: "hello world",
name: "title",
};
},
template: `<form action="https://www.baidu.com">
<button type="submit">提交</button>
</form>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
如果想阻止默认事件,首先想到的是,给元素绑定一个方法,在这个方法中阻止默认事件。
const app = Vue.createApp({
data() {
return {
content: "hello world",
name: "title",
};
},
methods: {
handleSubmit(e) {
e.preventDefault();
},
},
template: `<form action="https://www.baidu.com">
<button type="submit" @click="handleSubmit">提交</button>
</form>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
其实在Vue中,我们不需要写这么麻烦。Vue提供了.prevent
修饰符,可以帮助我们阻止默认行为。(@click.prevent="..."
)
const app = Vue.createApp({
data() {
return {
content: "hello world",
name: "title",
};
},
methods: {
handleSubmit() {
alert("我被点击了");
},
},
template: `<form action="https://www.baidu.com">
<button type="submit" @click.prevent="handleSubmit">提交</button>
</form>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
修饰符可以帮助我们简化一些常用代码的编写。
2.6 数据,方法,计算属性和侦听器(1)
本节内容:
- data
- methods
- computed
- watcher(侦听器)
2.6.1 data–数据
我们在定义数据的时候,是在创建Vue实例的时候,将数据写在data()
函数中,并以对象形式返回我们的数据。
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
methods: {},
template: `<div>{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
在浏览器的控制台里,我们可以使用如下代码来获取这个组件中的数据:
vm.$data.content
因为content是data中的第一层数据,因此我们想访问它,写法还可以被简化成这样:
vm.content
2.6.2 methods–方法
Vue实例中,所有被绑定的事件,都要写在methods对象中。
const app = Vue.createApp({
data() {
return {
content: "hello world",
};
},
methods: {
handleClick() {
console.log("click");
},
},
template: `<div @click="handleClick">{{content}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
⭐methods有几个需要注意的点:
-
在Vue的方法中,所有的this都统一指向对应的Vue实例。因此,如果要用到这一个特性,methods中的方法一定不能使用箭头函数。
-
除了将方法绑定在元素的事件上,还可以在插值表达式中使用methods中定义的方法。
const app = Vue.createApp({ data() { return { content: "hello world", }; }, methods: { handleClick() { console.log("click", this.content); }, formatString(string) { return string.toUpperCase(); }, }, template: `<div @click="handleClick">{{formatString(content)}}</div>`, }); // vm 代表的就是 Vue 应用的根组件 const vm = app.mount("#root");
2.6.3 computed–计算属性
computed计算属性,是依赖其他的数据属性,所计算出来的一个新的属性。
特点:只有当依赖的数据发生变化时,才会重新计算,返回新的计算属性。
举例:Vue实例中有两个数据,count代表数量,price代表单价。我们想在页面上显示出物品的总价,可以使用表达式,这么写:
const app = Vue.createApp({
data() {
return {
count: 2,
price: 5,
};
},
methods: {},
template: `<div>{{count * price}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这么写一点问题都没有。
但是理想情况下,我们应该让这些数据做到语义化。单独在页面上写{{count * price}}
难免会让人摸不着头脑。
如果我们有一个total属性,直接将其写在页面上{{total}}
,这显然比之前的写法在语义化上强不少。
实际上,Vue中的计算属性,就可以帮助我们做到这一点。
我们要在这个实例中定义一个computed对象,在其中可以写一些方法,这些方法被当作属性来使用。
const app = Vue.createApp({
data() {
return {
count: 2,
price: 5,
};
},
computed: {
total() {
return this.count * this.price;
},
},
template: `<div>{{total}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
把计算属性单独拎出来:
computed: {
total() {
return this.count * this.price;
},
},
这段代码的意思是,现在有一个计算属性,名叫total
,它的值始终等于this.count * this.price
。
定义了这个计算属性后,直接把名字拿出来,扔到插值表达式中使用就可以了。
如果一个计算属性依赖的数据发生了变化,这个计算属性则会重新进行计算,然后渲染到页面上。
⭐⭐既然使用一个method也能实现计算属性的功能,那么计算属性的意义在哪呢?
当计算属性依赖的内容发生变更时,才会重新执行计算;
使用method,只要页面重新渲染,就会重新计算。
计算属性内部会带一种缓存的机制,所以在做页面渲染的时候,计算属性会更高效一点
2.6.4 watcher–侦听器
watcher可以监听一个数据属性是否发生了变化。
要写一个侦听器,只需要定义一个watch对象。
如果遇到异步的情况,可以使用watch。比如当数据发生改变,等待5秒钟,输出字符串'change'
。
通过watch,可以监听我们在data中定义的数据是否发生了改变,并且可以做一些异步的操作。
举例:监听price这个数据,当他发生变化时,3秒后在控制台输出'price change'
。
const app = Vue.createApp({
data() {
return {
count: 2,
price: 5,
};
},
watch: {
price() {
setTimeout(() => {
console.log("price change");
}, 3000);
},
},
computed: {
total() {
return this.count * this.price;
},
},
template: `<div>{{total}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
在侦听器中,传入了两个参数,一个是数据改变后的值,另一个是数据改变之前的值。
watch: {
price(current, prev) {
console.log(current, prev);
},
},
现在通过侦听器watch来实现和computed计算属性中一样的效果:
const app = Vue.createApp({
data() {
return {
count: 2,
price: 5,
// 新增newTotal属性
newTotal: 10,
};
},
watch: {
// 监听price,当price发生改变时,修改newTotal的值
price(current, prev) {
this.newTotal = current * this.count;
},
},
computed: {
total() {
return this.count * this.price;
},
},
// 插值表达式中使用newTotal
template: `<div>{{newTotal}}</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这样,使用侦听器watch也可以实现和计算属性一样的效果,但是相比计算属性只有一行代码而言,watch的这种实现方式显然更加复杂。
所以,如果一个功能能同时用watch和computed来实现,推荐使用computed。
2.6.5 小结
- computed和method都能实现的功能,建议使用computed,因为有缓存。
- computed和watcher都能实现的功能,建议使用computed,因为更简洁。
2.7 样式绑定语法
2.7.1 通过字符串的形式改变样式(用到v-bind)
创建一个最简单的Vue实例。
const app = Vue.createApp({
template: `<div>hello world</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
定义两个样式:
.red {
color: red;
}
.green {
color: green;
}
Vue中使用样式,和平常写法一样,直接添加class。如下:
const app = Vue.createApp({
template: `<div class="red">hello world</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
问题来了。现在的class是写死的。
如果想通过数据控制文字的颜色,要怎么做?
简单,用v-bind
。
const app = Vue.createApp({
data() {
return {
classString: "red",
};
},
template: `<div :class="classString">hello world</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这样就通过使用字符串来控制文字的颜色,修改vm.classString='green'
就可以把文字颜色改成绿的。
除了这种通过字符串的方式改变数据,Vue还扩增了一些语法。
2.7.2 通过对象的形式改变样式
const app = Vue.createApp({
data() {
return {
classString: "red",
classObject: { red: true, green: true },
};
},
template: `<div :class="classObject">hello world</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这里定义了一个classObject
对象。<div>
标签的样式是由这个对象决定的。
这个对象的属性名表示对应class的名字,属性值表示要不要展示这个class。
2.7.3 通过数组的形式改变样式
const app = Vue.createApp({
data() {
return {
classString: "red",
classArray: ["red", "green"],
};
},
template: `<div :class="classArray">hello world</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这里使用数组来控制<div>
标签的样式。数组classArray
的内容是所有要添加到这个标签上的class名字。
数组中同样可以包含对象,这和使用对象控制样式的含义是一样的。
const app = Vue.createApp({
data() {
return {
classString: "red",
classArray: ["red", "green", {brown: true}],
};
},
template: `<div :class="classArray">hello world</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.7.4 父子组件的样式
现在创建一个Vue实例,并且添加一个名为demo的子组件。
在子组件上直接添加class的名称,就可以为其修改样式。
const app = Vue.createApp({
data() {
return {
classString: "red",
classObject: { red: true, green: true },
classArray: ["red", "green"],
};
},
template: `
<div :class="classString">
hello world
<demo />
</div>`,
});
app.component("demo", {
template: `<div class="green">single</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
demo子组件最外层只有一个<div>
标签,那我们除了可以把样式写在子组件定义时候的标签上,还可以在调用这个子组件的时候为其添加class,比如这样:
const app = Vue.createApp({
data() {
return {
classString: "red",
classObject: { red: true, green: true },
classArray: ["red", "green"],
};
},
// 调用子组件时添加class
template: `
<div :class="classString">
hello world
<demo class="green"/>
</div>`,
});
app.component("demo", {
template: `<div>single</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
如果子组件最外层不是只有一个节点,而是有两个或者更多,那么就不能在调用子组件时为其添加样式。
比如这样的子组件:
app.component("demo", {
template: `
<div>one</div>
<div>two</div>
`,
});
这个子组件最外层有两个<div>
,所以不能在父组件调用子组件时为其添加class。如果这么做,添加的样式不会生效。
如果想要子组件有两个以上的最外层标签,同时,想在调用时再为其添加样式,有办法吗?
2.7.5 $attrs.class
如果子组件有两个以上的最外层标签,并且要在父组件调用子组件的时候添加样式,需要在子组件的标签上绑定:class="$attrs.class"
。
const app = Vue.createApp({
data() {
return {
classString: "red",
classObject: { red: true, green: true },
classArray: ["red", "green"],
};
},
// 调用子组件时添加class
template: `
<div :class="classString">
hello world
<demo class="green"/>
</div>`,
});
app.component("demo", {
template: `
<div :class="$attrs.class">one</div>
<div>two</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.7.6 行内样式
Vue中写行内样式,和在HTML页面中书写行内样式是一样的。
const app = Vue.createApp({
data() {
return {
classString: "red",
classObject: { red: true, green: true },
classArray: ["red", "green"],
};
},
// 添加行内样式
template: `
<div style="color: blue;">
hello world
</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.7.7 字符串形式绑定行内样式
同样,使用v-bind绑定变量,变量中储存行内样式的字符串。
const app = Vue.createApp({
data() {
return {
styleString: "color: blue;",
};
},
// v-bind绑定行内样式字符串
template: `
<div :style="styleString">
hello world
</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.7.8 对象形式绑定行内样式(推荐使用)
Vue做了一些扩展,允许以对象形式书写行内样式。
const app = Vue.createApp({
data() {
return {
styleString: "color: blue;",
styleObject: {
color: "orange",
background: "yellow",
},
};
},
// 对象形式添加行内样式
template: `
<div :style="styleObject">
hello world
</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.8 条件渲染(v-if指令、v-show指令)
2.8.1 v-if指令
v-if
控制一个标签是否要展示。要给它一个布尔值。
const app = Vue.createApp({
data() {
return {
show: true,
};
},
template: `<div v-if="show">v-if</div>`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
v-if
指令是通过控制标签在DOM上的存在与否,来控制这个元素要显示还是隐藏。
2.8.2 v-show指令
v-show同样也是控制一个标签是否要展示。要给它一个布尔值。
const app = Vue.createApp({
data() {
return {
show: true,
};
},
template: `
<div v-if="show">v-if</div>
<div v-show="show">v-show</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
和v-if
不同的是,v-show
是通过style样式来控制的。如果v-show
接收到的值为false
,那么就给这个元素添加style="display:none;"
;如果v-show
接收到的值为true,则把style="display:none;"
去掉。
2.8.3 v-if和v-show的比较
v-if
和v-show
都是用来控制DOM元素的展示与否,这就引申出来一个问题:到底哪个更好?
- 如果我们要频繁改变一个DOM元素的展示与否,建议使用
v-show
。因为v-show
不会频繁销毁DOM,在性能上会更好一点; - 如果不涉及频繁改变DOM元素,其实
v-if
和v-show
都差不多。根据具体的场景选择即可。
2.8.4 v-if的其他用法(v-else指令、v-else-if指令)
v-if
还可以与v-else
配套使用。
const app = Vue.createApp({
data() {
return {
show: false,
conditionOne: true,
};
},
template: `
<div v-if="conditionOne">v-if</div>
<div v-else>else</div>
<div v-show="show">v-show</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这段代码中,如果conditionOne
的值为true
,则显示<div v-if="conditionOne">v-if</div>
这个DOM元素;如果conditionOne
的值为false
,则显示<div v-else>else</div>
这个元素。这个逻辑和if-else语句是一样的。
需要注意的一点是,如果要将v-if
和v-else
结合起来使用,要将这两个指令紧贴在一起写。
JS中有if - else if - else
的语法,Vue中也同样有类似的指令:v-else-if
const app = Vue.createApp({
data() {
return {
show: false,
conditionOne: false,
conditionTwo: true,
};
},
template: `
<div v-if="conditionOne">v-if</div>
<div v-else-if="conditionTwo">v-else-if</div>
<div v-else>else</div>
<div v-show="show">v-show</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这段代码的逻辑如下:
- 如果
conditionOne
值为true
,则渲染<div v-if="conditionOne">v-if</div>
;否则,看下一行。 - 如果
conditionTwo
值为true
,则渲染<div v-else-if="conditionTwo">v-else-if</div>
;否则,看下一行。(这里代码中为true,会渲染这个DOM元素,后面的v-else不渲染) - 前面两个值都为false,于是轮到了v-else这个指令,直接渲染
<div v-else>else</div>
。
同样要注意的是,这三个指令要紧挨着写。中间不能有其他的东西。
2.9 列表循环渲染(1)
使用v-for
指令。1.3小节中详细写过,这里复习一下用法。
const app = Vue.createApp({
data() {
return {
list: ["hello", "world", "item"],
};
},
template: `
<ul>
<li v-for="(item, index) in list">{{index}}--{{item}}</li>
</ul>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
v-for
除了对数组进行循环,还能对对象进行循环。循环对象的时候,可以接收三个参数,顺序依次是:(属性值,属性名,索引)
const app = Vue.createApp({
data() {
return {
listArray: ["hello", "world", "item"],
listObject: {
first: "hello",
second: "world",
third: "bye",
},
};
},
template: `
<ul>
<li v-for="(value, key, index) in listObject">
{{value}}--{{key}}--{{index}}
</li>
</ul>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
页面显示结果:
- hello–first–0
- world–second–1
- bye–third–2
2.9.1 v-for的key值
回到遍历数组上来。
当被遍历的数组中的值发生改变时,页面会重新渲染。
比如下面这段代码,添加一个按钮,每次点击,都往listArray
中新增数据。
const app = Vue.createApp({
data() {
return {
listArray: ["hello", "world", "item"],
};
},
methods: {
handleBtnClick() {
this.listArray.push("new item");
},
},
template: `
<button @click="handleBtnClick">新增</button>
<ul>
<li v-for="(item, index) in listArray">
{{index}}--{{item}}
</li>
</ul>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这里有一个问题。只要数据发生改变,页面就会重新渲染,但是原本页面上的内容并没有发生改变,只是新增了一些DOM元素,但是原来页面上的那些DOM元素也依然会被重新渲染,这就造成了性能上的一些浪费。
Vue底层为了优化性能,会尽量让那些能够复用的DOM元素进行复用。但是有些情况下,Vue不知道有些东西到底应不应该复用。
这时候,为了更好地辅助Vue,让Vue的效率、性能更高,在使用v-for指令的时候,最好给每一项添加一个唯一的key值。比如:
<li v-for="(item, index) in listArray" :key="item">
{{index}}--{{item}}
</li>
有了key值之后,列表在渲染的时候,如果在第二次渲染的时候,key值没有发生改变,Vue就会去查看之前key值对应的DOM元素是否能够在本次渲染中复用。如果能复用,就不会再去创建这个DOM元素了,这样能够提升一些性能。
⭐小结:当使用v-for
做循环时,循环的每一项要尽量给一个唯一的key,以提升性能。
2.9.2 数组的变更函数
当数组中内容发生变化,页面会重新渲染。有几个变更函数可以让数组发生变化:
push, pop, shift, unshift, splice, sort, reverse
2.9.3 直接替换数组
直接替换数组的内容也可以让页面重新渲染。
this.listArray = [1, 2, 3];
this.listArray = ['bye'].concat(['world']);
2.9.4 直接更新数组的内容
改变数组某一项的内容,也可以使页面重新渲染。
this.listArray[1] = 'hello';
2.10 列表循环渲染(2)
上一节中讲到了如何对数组形式的数据进行更改。
现在来介绍如何对对象形式的数据进行更改。
const app = Vue.createApp({
data() {
return {
listObject: {
first: "hello",
second: "world",
third: "bye",
},
};
},
template: `
<ul>
<li v-for="(value, key, index) in listObject" :key="index">
{{key}}--{{value}}--{{index}}
</li>
</ul>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.10.1 直接添加对象的内容
直接添加对象的内容,也可以直接展示出来。
const app = Vue.createApp({
data() {
return {
listObject: {
first: "hello",
second: "world",
third: "bye",
},
};
},
methods: {
handleBtnClick() {
this.listObject.name = "mike";
this.listObject.sex = "male";
},
},
template: `
<button @click="handleBtnClick">新增</button>
<ul>
<li v-for="(value, key, index) in listObject" :key="index">
{{key}}--{{value}}--{{index}}
</li>
</ul>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.10.2 不显示某一项的内容
现在listObject中有三项:
listObject: {
first: "hello",
second: "world",
third: "bye",
},
使用v-for
对其进行遍历时,我们希望第二项second: "world"
不出现在页面上。该怎么做?
这里想到使用v-if
指令。
错误的写法:
const app = Vue.createApp({
data() {
return {
listArray: ["hello", "world", "item"],
listObject: {
first: "hello",
second: "world",
third: "bye",
},
};
},
methods: {
handleBtnClick() {
this.listObject.name = "mike";
this.listObject.sex = "male";
},
},
template: `
<button @click="handleBtnClick">新增</button>
<ul>
<li v-for="(value, key, index) in listObject"
:key="index"
v-if="key !== 'second'"
>
{{key}}--{{value}}--{{index}}
</li>
</ul>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
v-for
和v-if
不能写在同一个标签上,因为v-fo
r的优先级比v-if
等级高,会导致v-if失效。
我们需要把它们写在不同的标签上,比如这样:
const app = Vue.createApp({
data() {
return {
listArray: ["hello", "world", "item"],
listObject: {
first: "hello",
second: "world",
third: "bye",
},
};
},
methods: {
handleBtnClick() {
this.listObject.name = "mike";
this.listObject.sex = "male";
},
},
template: `
<button @click="handleBtnClick">新增</button>
<div v-for="(value, key, index) in listObject"
:key="index"
>
<span v-if="key !== 'second'">
{{key}}--{{value}}--{{index}}
</span>
</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
在v-for
的标签里面,添加一个带有v-if
的标签,来控制是否要显示对应key
的属性值。
这样就可以控制“过滤”掉某一项的内容。
2.10.3 template占位符
上一小节的写法其实存在一些问题。
我们本身只想过滤掉某一项的内容,让他不显示,所以在v-for
所在的标签里面又添加了一个标签。
因此,页面上多出来一个标签。但是我们本不想让他出现。
这时就可以使用<template>
占位符标签。
<template>
长得像一个DOM元素,但其实它只是一个占位符,并不会被渲染。
const app = Vue.createApp({
data() {
return {
listArray: ["hello", "world", "item"],
listObject: {
first: "hello",
second: "world",
third: "bye",
},
};
},
methods: {
handleBtnClick() {
this.listObject.name = "mike";
this.listObject.sex = "male";
},
},
template: `
<button @click="handleBtnClick">新增</button>
<template v-for="(value, key, index) in listObject"
:key="index"
>
<div v-if="key !== 'second'">
{{key}}--{{value}}--{{index}}
</div>
</template>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.11 事件绑定——事件修饰符(1)
本节学习Vue中事件相关的内容。
2.11.1 获取原生event对象
看一段代码。这段代码会在页面上展示一个数字和一个按钮,每点击一次按钮,数字会+1。
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleBtnClick() {
this.counter += 1;
},
},
template: `
{{counter}}
<button @click="handleBtnClick">Button</button>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
绑定的事件函数可以接收到一个event
对象:
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleBtnClick(event) {
this.counter += 1;
console.log(event.target); // <button>Button</button>
},
},
template: `
{{counter}}
<button @click="handleBtnClick">Button</button>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
如果当点击按钮时,想额外传其他参数,可以直接在v-on:click
后面的函数中传参。比如:
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleBtnClick(num) {
this.counter += num;
},
},
template: `
{{counter}}
<button @click="handleBtnClick(2)">Button</button>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
但是这样做,对应的函数就无法接收到event
对象。
想要在传入其他参数的同时,还要传递event
对象,可以在v-on:click
的函数中传一个$event
。
<button @click="handleBtnClick(2, $event)">Button</button>
这样,methods中对应的方法就能接收到event
。
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleBtnClick(num, event) {
this.counter += num;
console.log(event.target); // <button>Button</button>
},
},
template: `
{{counter}}
<button @click="handleBtnClick(2, $event)">Button</button>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
所以,想要额外传递参数,同时要获取到原生的event对象,就需要在模板中使用$event
。
2.11.2 为一个事件绑定多个函数
假设点击按钮时,想触发两个函数。这两个函数应该绑定到v-on:click上。但是不能直接绑定函数的引用,比如这样:
// 错误的写法
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleBtnClick1() {
alert(1);
},
handleBtnClick2() {
alert(2);
},
},
// 错误的写法
template: `
{{counter}}
<button @click="handleBtnClick1, handleBtnClick2">Button</button>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
在绑定多个事件的时候,要把括号带上。
// 正确的写法
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleBtnClick1() {
alert(1);
},
handleBtnClick2() {
alert(2);
},
},
// 正确的写法
template: `
{{counter}}
<button @click="handleBtnClick1(), handleBtnClick2()">Button</button>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.11.3 事件修饰符.stop——阻止冒泡
现在有一个模板,内容是一个<div>
套一个<div>
,在这两个<div>
上都绑定click事件,那么,点击内层的<div>
,事件会冒泡,触发父级<div>
绑定的事件。代码如下:
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleDivClick1() {
alert(1);
},
handleDivClick2() {
alert(2);
},
},
template: `
<div @click="handleDivClick1">
<div @click="handleDivClick2">123</div>
</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
如果我们想阻止事件向上层冒泡,触发父级元素绑定的事件,就要用到.stop
事件修饰符。用法如下:
template: `
<div @click="handleDivClick1">
<div @click.stop="handleDivClick2">123</div>
</div>
`,
在子元素的@click
上添加一个.stop
即可。
2.11.4 事件修饰符.self
现在依然有两个嵌套的<div>
,最外层<div>
中除了嵌套了一个<div>
,还有一些其它内容。
最外层<div>
上绑定一个click事件。当点击内部的<div>
或者内部的其他元素时,这个click事件都会触发。
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleDivClick() {
alert(1);
},
},
template: `
<div @click="handleDivClick">
最外层div中的文字
<div>最内层div中的文字</div>
</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
现在我只想让最外层的div
被点击时才能触发绑定的事件,就要用到.self
修饰符。.self
的作用是,只当在 event.target 是当前元素自身时触发处理函数,即事件不是从内部元素触发的。
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleDivClick() {
alert(1);
},
},
template: `
<div @click.self="handleDivClick">
最外层div中的文字
<div>最内层div中的文字</div>
</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.11.5 事件修饰符.prevent
.prevent
修饰符用于阻止默认事件。在2.5.4小节中已经详细介绍过,不再赘述。
2.11.6 事件修饰符.capture
.capture
修饰符,表示添加事件监听器时使用事件捕获模式(从外到内)。默认情况下使用的是冒泡模式(从内到外),使用.capture
修饰符可以修改冒泡模式为捕获模式。
2.11.7 事件修饰符.once
.once
修饰符,代表对应绑定的事件只会执行一次。执行后不会再被触发。
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
handleDivClick() {
alert("我只会弹出一次,关了就没有了。");
},
},
template: `
<div @click.once="handleDivClick">
这个div上绑定的事件只会被触发一次!
</div>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.11.8 事件修饰符.passive
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。加上passive就是为了告诉浏览器,不用查询了,我们没用preventDefault阻止默认动作。
可以提高性能,尤其是移动端的性能。
2.12 事件绑定(2)
除了上节讲到的事件修饰符,还有按键修饰符、鼠标按钮修饰符、精确修饰符。
2.13 表单中双向绑定指令的使用(1)
双向绑定一般都和表单中的元素相关,比如<input>
,checkbox
, radio
, <select>
等。
2.13.1 v-model指令
使用v-model
指令可以进行双向绑定。
const app = Vue.createApp({
data() {
return {
message: "hello",
};
},
template: `
{{message}}
<input v-model="message"/>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
输入框中的内容和message
的值绑定在一起。当input框中的内容发生改变,message的值也会随之改变,页面上显示的内容也会改变。
<textarea v-model="message"/>
2.13.2 checkbox使用v-model
定义三个checkbox类型的input。
当在checkbox上使用v-model,可以使用一个数组来存储勾选的内容。
const app = Vue.createApp({
data() {
return {
message: [],
};
},
template: `
{{message}}
1:<input type="checkbox" v-model="message" value="1"/>
2:<input type="checkbox" v-model="message" value="2"/>
3:<input type="checkbox" v-model="message" value="3"/>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
当某一项被勾选时,该项的value
值就会被push进message
数组中。
2.13.3 radio使用v-model
radio和checkbox相似,只不过radio是单选框,每次只能选中一个选项,用数组存储意义不大。直接用字符串存储即可。
const app = Vue.createApp({
data() {
return {
message: "",
};
},
template: `
{{message}}
1:<input type="radio" v-model="message" value="1"/>
2:<input type="radio" v-model="message" value="2"/>
3:<input type="radio" v-model="message" value="3"/>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.13.4 select使用v-model
在<select>
标签上绑定v-model。
const app = Vue.createApp({
data() {
return {
message: "",
};
},
template: `
{{message}}
<select v-model="message">
<option disabled>--请选择数据--</option>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
这样,选中的内容和message
就进行了绑定。
⭐如果select可以多选,那么就可以和一个数组使用v-model进行双向绑定。
const app = Vue.createApp({
data() {
return {
message: [],
};
},
template: `
{{message}}
<select v-model="message" multiple>
<option disabled>--请选择数据--</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
⭐可以使用v-for来循环展示option选项。
const app = Vue.createApp({
data() {
return {
message: [],
options: [
{
text: "A",
value: "A",
},
{
text: "B",
value: "B",
},
{
text: "C",
value: "C",
},
],
};
},
template: `
{{message}}
<select v-model="message" multiple>
<option disabled>--请选择数据--</option>
<option v-for="item in options" :value="item.value">{{item.text}}</option>
</select>
`,
});
// vm 代表的就是 Vue 应用的根组件
const vm = app.mount("#root");
2.14 表单中双向绑定指令的使用(2)
2.14.1 修饰符.lazy
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 。可以添加 lazy
修饰符,从而转为在输入框失焦之后进行同步。
<!-- 在“onblur”时而非“input”时更新 -->
<input v-model.lazy="msg">
2.14.2 修饰符.number
如果想自动将用户的输入值转为数值类型,可以给 v-model
添加 number
修饰符:
<input v-model.number="age" type="number">
2.14.3 修饰符.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model
添加 trim
修饰符:
<input v-model.trim="msg">