1.属性绑定v-bind(:)
v-bind
是 Vue 2 中用于动态绑定属性的核心指令,它支持多种语法和用法,能够灵活地绑定 DOM 属性、组件 prop,甚至动态属性名。通过 v-bind
,可以实现数据与视图之间的高效同步,是构建动态界面的重要工具。
<template>
<div class="demo-container">
<!-- 基础属性绑定 -->
<div :id="dynamicId">动态 ID 的 div</div>
<!-- 绑定多个属性 -->
<div :="{ id: dynamicId, title: dynamicTitle, class: 'my-class' }">
绑定多个属性
</div>
<!-- 动态属性名 -->
<div :[attributeName]="attributeValue">
动态属性名绑定
</div>
<!-- 布尔属性绑定 -->
<button :disabled="isDisabled">点击我</button>
<!-- 绑定组件的 prop -->
<child-component :message="parentMessage" :title.sync="parentTitle"></child-component>
</div>
</template>
<script>
// 定义子组件
const ChildComponent = {
props: {
message: String,
title: String
},
template: `
<div>
<h3>子组件</h3>
<p>从父组件接收到的 message: {{ message }}</p>
<p>从父组件接收到的 title: {{ title }}</p>
<button @click="updateTitle">更新父组件的 title</button>
</div>
`,
methods: {
updateTitle() {
// 使用 $emit 触发父组件的更新
this.$emit('update:title', '新的标题');
}
}
};
export default {
name: "demo",
components: {
ChildComponent
},
data() {
return {
dynamicId: 'my-dynamic-id', // 动态 ID
dynamicTitle: '这是一个标题', // 动态标题
attributeName: 'class', // 动态属性名
attributeValue: 'my-class', // 动态属性值
isDisabled: false, // 布尔属性
parentMessage: 'Hello from parent!', // 父组件的 message
parentTitle: '初始标题' // 父组件的 title
};
}
};
</script>
<style scoped>
.demo-container {
margin: 20px;
padding: 20px;
border: 1px solid #ccc;
}
.my-class {
color: blue;
font-weight: bold;
}
button {
margin-top: 10px;
}
</style>
1.1示例代码中的父子组件通信
-
父组件向子组件传递数据
-
父组件在模板中使用
:message="parentMessage"
和:title.sync="parentTitle"
。 -
Vue 会将
parentMessage
和parentTitle
的值传递给子组件的message
和title
。 -
子组件通过
props
接收这些值,并可以在模板中使用。
-
-
子组件向父组件传递事件
-
子组件在模板中有一个按钮,点击按钮时调用
updateTitle
方法。 -
updateTitle
方法通过this.$emit('update:title', '新的标题')
触发一个自定义事件update:title
,并传递新值'新的标题'
。 -
父组件监听到
update:title
事件后,会自动更新parentTitle
的值为'新的标题'
。
-
1.2面试问题:
-
如何实现父子组件之间的数据传递?
-
父组件如何向子组件传递数据?
-
子组件如何向父组件传递事件?
回答要点:
-
父组件向子组件传递数据: 使用
props
。-
父组件通过
v-bind
将数据绑定到子组件的props
。 -
子组件通过
props
接收父组件传递的数据。
-
-
子组件向父组件传递事件: 使用
$emit
。-
子组件通过
this.$emit
触发一个自定义事件,并传递数据。 -
父组件通过监听子组件的事件来接收数据。
<!-- 父组件 --> <template> <div> <child-component :message="parentMessage" @update:title="handleTitleUpdate"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { parentMessage: 'Hello from parent!', parentTitle: 'Initial Title' }; }, methods: { handleTitleUpdate(newTitle) { this.parentTitle = newTitle; } } }; </script>
<!-- 子组件 --> <template> <div> <p>Message from parent: {{ message }}</p> <button @click="updateTitle">Update Parent Title</button> </div> </template> <script> export default { props: { message: String }, methods: { updateTitle() { this.$emit('update:title', 'New Title'); } } }; </script>
-
.sync
修饰符的作用-
简化父子组件之间的双向绑定。
-
-
2.事件绑定 v-on(@)
v-on
是 Vue.js 中用于绑定事件监听器的指令,它允许你为 DOM 元素或组件绑定事件处理函数。通过 v-on
,你可以监听用户的交互行为(如点击、输入等),并在事件触发时执行特定的逻辑。
<template>
<div>
<h1>事件绑定示例</h1>
<button @click="handleClick">点击我</button>
<input type="text" @input="handleInput($event)">
<a href="https://example.com" @click.prevent="handleLinkClick">链接</a>
<div @click="handleDivClick">
<button @click.stop="handleButtonClick">点击我</button>
</div>
<input type="text" @keyup.enter="handleSubmit">
</div>
</template>
<script>
export default {
methods: {
handleClick() {
alert('按钮被点击了!');
},
handleInput(event) {
console.log('输入框的值:', event.target.value);
},
handleLinkClick() {
alert('链接被点击了,但不会跳转!');
},
handleDivClick() {
alert('div 被点击了!');
},
handleButtonClick() {
alert('按钮被点击了,但不会触发 div 的点击事件!');
},
handleSubmit() {
alert('回车键被按下,表单提交!');
}
}
};
</script>
2.1基本用法
1. 监听原生 DOM 事件
v-on
可以用来监听原生 DOM 事件,例如 click
、input
、mouseover
等。
<button @click="handleClick">点击我</button>
2. 监听组件事件
v-on
也可以用来监听自定义组件的事件。子组件通过 $emit
触发事件,父组件通过 v-on
监听这些事件。
<child-component @custom-event="handleCustomEvent"></child-component>
-
custom-event
是子组件触发的自定义事件。 -
handleCustomEvent
是父组件中定义的事件处理函数。
3. 传递事件参数
在事件处理函数中,你可能需要访问事件对象(例如获取输入框的值或鼠标的位置)。可以通过 $event
获取事件对象。
<input type="text" @input="handleInput($event)">
4. 传递额外参数
除了事件对象,你还可以传递其他参数到事件处理函数。
<button @click="handleClick('Hello', $event)">点击我</button>
methods: {
handleClick(message, event) {
console.log(message); // 输出 "Hello"
console.log(event.type); // 输出 "click"
}
}
5.事件修饰符
Vue 为 v-on
提供了一些事件修饰符,用于更方便地处理常见的事件行为。
.stop
:阻止事件冒泡
-
点击按钮时,
handleButtonClick
会被触发,但不会触发handleDivClick
。
<div @click="handleDivClick">
<button @click.stop="handleButtonClick">点击我</button>
</div>
.prevent
:阻止默认行为
-
点击链接时,不会跳转到
https://example.com
,因为默认行为被阻止了。
<a href="https://example.com" @click.prevent="handleLinkClick">链接</a>
.capture
:使用事件捕获模式
-
在事件冒泡阶段,
handleDivClick
会在handleButtonClick
之前被触发。
<div @click.capture="handleDivClick">
<button @click="handleButtonClick">点击我</button>
</div>
.self
:只触发绑定元素自身的事件
-
只有直接点击按钮时,
handleButtonClick
才会被触发。
<div @click="handleDivClick">
<button @click.self="handleButtonClick">点击我</button>
</div>
.once
:事件只触发一次
-
handleClick
只会在第一次点击时被触发,之后的点击不会触发。
2.2总结
v-on
是 Vue 中非常强大的指令,用于绑定事件监听器。它支持以下功能:
-
监听原生 DOM 事件和自定义组件事件。
-
传递事件对象和额外参数。
-
使用事件修饰符(如
.stop
、.prevent
、.capture
等)简化事件处理逻辑。 -
使用键盘修饰符(如
.enter
、.tab
等)处理键盘事件。
3.双向绑定v-model
v-model
是 Vue 中实现双向数据绑定的核心指令,它允许你将表单输入和应用状态进行同步。通过 v-model
,表单元素的值会自动与 Vue 实例的数据保持一致,同时用户对表单的修改也会实时更新到数据中,反之亦然。这种双向绑定机制是 Vue 的一大特色,极大地简化了表单处理逻辑。
3.1基本用法
<template>
<div class="v-model-demo">
<h2>v-model 双向绑定示例</h2>
<!-- 输入框 -->
<div>
<label for="text-input">输入框:</label>
<input id="text-input" v-model="message" placeholder="输入内容">
<p>输入的内容是:{{ message }}</p>
</div>
<!-- 多行文本框 -->
<div>
<label for="textarea">多行文本框:</label>
<textarea id="textarea" v-model="multiLineMessage" placeholder="输入多行内容"></textarea>
<p>输入的内容是:</p>
<p style="white-space: pre">{{ multiLineMessage }}</p>
</div>
<!-- 单个复选框 -->
<div>
<label><input type="checkbox" v-model="singleCheckbox"> 单个复选框</label>
<p>复选框是否选中:{{ singleCheckbox }}</p>
</div>
<!-- 多个复选框 -->
<div>
<label><input type="checkbox" v-model="checkedCities" value="北京"> 北京</label>
<label><input type="checkbox" v-model="checkedCities" value="上海"> 上海</label>
<label><input type="checkbox" v-model="checkedCities" value="广州"> 广州</label>
<p>选中的城市:{{ checkedCities }}</p>
</div>
<!-- 单选按钮 -->
<div>
<label><input type="radio" v-model="picked" value="A"> A</label>
<label><input type="radio" v-model="picked" value="B"> B</label>
<p>选中的选项是:{{ picked }}</p>
</div>
<!-- 下拉选择框 -->
<div>
<label for="select">下拉选择框:</label>
<select id="select" v-model="selected">
<option disabled value="">请选择</option>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
</select>
<p>选中的城市是:{{ selected }}</p>
</div>
</div>
</template>
<script>
export default {
name: "VModelDemo",
data() {
return {
message: "", // 输入框绑定的数据
multiLineMessage: "", // 多行文本框绑定的数据
singleCheckbox: false, // 单个复选框绑定的数据
checkedCities: [], // 多个复选框绑定的数据
picked: "", // 单选按钮绑定的数据
selected: "" // 下拉选择框绑定的数据
};
}
};
</script>
<style scoped>
.v-model-demo {
margin: 20px;
font-family: Arial, sans-serif;
}
label {
margin-right: 10px;
}
p {
margin: 10px 0;
}
textarea {
width: 100%;
height: 100px;
}
select {
width: 100%;
}
</style>
v-model
的工作原理
v-model
实际上是一个语法糖,它背后做了以下几件事:
-
绑定
value
属性:-
对于
<input>
和<textarea>
,v-model
会绑定value
属性。 -
对于
<select>
,v-model
会绑定value
属性到选中的<option>
。 -
对于
<input type="checkbox">
和<input type="radio">
,v-model
会绑定value
属性到对应的值。
-
-
监听
input
或change
事件:-
v-model
会监听表单元素的input
事件(对于<input>
和<textarea>
)或change
事件(对于<select>
、<input type="checkbox">
和<input type="radio">
)。 -
当事件触发时,它会自动更新绑定的数据。
-
3.2v-model
修饰符
<template>
<div class="v-model-modifiers-demo">
<h2>v-model 修饰符示例</h2>
<!-- .lazy 修饰符 -->
<div>
<label for="lazy-input">输入框(.lazy):</label>
<input id="lazy-input" v-model.lazy="lazyMessage" placeholder="输入内容">
<p>输入的内容是:{{ lazyMessage }}</p>
<!--
.lazy 修饰符:
- 默认情况下,v-model 在每次 input 事件触发时更新数据。
- 使用 .lazy 修饰符后,数据会在 change 事件触发时更新,即用户离开输入框时。
-->
</div>
<!-- .number 修饰符 -->
<div>
<label for="number-input">输入框(.number):</label>
<input id="number-input" v-model.number="numberValue" type="number" placeholder="输入数字">
<p>输入的数字是:{{ numberValue }}</p>
<!--
.number 修饰符:
- 默认情况下,v-model 会将输入框的值作为字符串处理。
- 使用 .number 修饰符后,输入框的值会自动转换为数字类型。
-->
</div>
<!-- .trim 修饰符 -->
<div>
<label for="trim-input">输入框(.trim):</label>
<input id="trim-input" v-model.trim="trimMessage" placeholder="输入内容">
<p>输入的内容是:{{ trimMessage }}</p>
<!--
.trim 修饰符:
- 默认情况下,v-model 会保留输入框的首尾空格。
- 使用 .trim 修饰符后,输入框的值会自动去除首尾空格。
-->
</div>
</div>
</template>
<script>
export default {
name: "VModelModifiersDemo",
data() {
return {
lazyMessage: "", // .lazy 修饰符绑定的数据
numberValue: 0, // .number 修饰符绑定的数据
trimMessage: "" // .trim 修饰符绑定的数据
};
}
};
</script>
<style scoped>
.v-model-modifiers-demo {
margin: 20px;
font-family: Arial, sans-serif;
}
label {
margin-right: 10px;
}
p {
margin: 10px 0;
}
input {
width: 100%;
padding: 8px;
margin-bottom: 10px;
}
</style>
-
输入框(.lazy):
-
用户输入内容时,数据不会立即更新,直到用户离开输入框(触发
change
事件)。 -
{{ lazyMessage }}
会显示最终的输入内容。
-
-
输入框(.number):
-
用户输入数字时,数据会自动转换为数字类型。
-
{{ numberValue }}
会显示数字类型的值。
-
-
输入框(.trim):
-
用户输入内容时,首尾空格会被自动去除。
-
{{ trimMessage }}
会显示去除首尾空格后的内容。
-
3.3自定义组件中的 v-model
在自定义组件中,v-model
默认绑定的是子组件的 value
属性和 input
事件。如果你需要自定义 v-model
的行为,可以通过 props
和 $emit
来实现。
<template>
<div>
<custom-input v-model="message"></custom-input>
<p>输入的内容是:{{ message }}</p>
</div>
</template>
<script>
import CustomInput from './CustomInput.vue';
export default {
components: {
CustomInput
},
data() {
return {
message: ''
};
}
};
</script>
<!-- CustomInput.vue -->
<template>
<input
:value="value"
@input="$emit('input', $event.target.value)"
placeholder="输入内容"
>
</template>
<script>
export default {
props: ['value']
};
</script>
-
工作原理
-
父组件传递数据到子组件:
-
父组件通过
v-model="message"
将message
的值传递给子组件的value
prop
。 -
子组件的
value
prop
会接收这个值,并将其绑定到输入框的value
属性上。
-
-
子组件向父组件发送数据:
-
当用户在输入框中输入内容时,
input
事件被触发。 -
子组件通过
$emit('input', $event.target.value)
将用户输入的值发送回父组件。 -
父组件监听到
input
事件后,会更新message
的值。
-
-
双向绑定:
-
父组件的
message
和子组件的输入框内容始终保持同步。 -
用户在输入框中输入的内容会实时更新到父组件的
message
中。 -
父组件的
message
如果发生变化,输入框的内容也会自动更新。
-
4.计算属性 Computed
在 Vue 2 中,计算属性(Computed Properties)是一种非常强大的功能,它允许你基于 Vue 实例的数据动态计算值。计算属性是响应式的,当依赖的响应式数据发生变化时,计算属性会自动重新计算并更新。
计算属性通常用于以下场景:
-
基于现有数据派生新数据:例如,将用户的输入转换为大写或计算总价。
-
简化模板逻辑:避免在模板中编写复杂的逻辑。
-
缓存计算结果:计算属性会缓存结果,只有当依赖的数据发生变化时才会重新计算。
计算属性通过 computed
选项定义。计算属性的值由一个函数返回,这个函数的返回值会自动绑定到模板中。
<template>
<div>
<p>原字符串:{{ message }}</p>
<p>大写字符串:{{ upperCaseMessage }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: 'hello'
};
},
computed: {
upperCaseMessage() {
return this.message.toUpperCase();
}
}
};
</script>
-
data
:定义了响应式数据message
。 -
computed
:定义了计算属性upperCaseMessage
。-
upperCaseMessage
是一个函数,返回message
的大写形式。 -
计算属性的值会自动更新,当
message
发生变化时,upperCaseMessage
也会重新计算。
-
计算属性的缓存机制
计算属性是基于它们的依赖进行缓存的。只有当依赖的响应式数据发生变化时,计算属性才会重新计算。这意味着如果你的依赖数据没有变化,计算属性的值不会重新计算,从而提高性能。
计算属性与方法的区别
计算属性和方法都可以基于数据动态计算值,但它们有一些关键区别:
-
缓存机制:
-
计算属性:会缓存结果,只有当依赖的响应式数据发生变化时才会重新计算。
-
方法:每次调用都会重新计算,不会缓存结果。
-
-
使用场景:
-
计算属性:适用于基于现有数据派生新数据的场景,尤其是需要缓存结果的场景。
-
方法:适用于需要动态执行的逻辑,例如事件处理函数。
-