Vue的引用
// Vue2在线引入
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
// Vue3在线引入
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
// Axios在线引入
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Vue的创建
vue中productionTip的全局配置
作用:阻止vue在启动时生成生产提示
Vue.config.productionTip = false
方法一
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> </head> <body> <!-- 准备好容器--> <div id="app"> {{message}} </div> <div class="app2"> {{message}} </div> <p> {{message}} </p> </body> </html> <script> // 阻止vue在启动时生成生产提示 Vue.config.productionTip = false // 创建Vue实例 new Vue({ el:'#app', data:{ message:'hello world' } }) new Vue({ el:'.app2', data:{ message:'hello world' } }) new Vue({ el:'p', data:{ message:'hello world' } }) </script>
方法二(data的两种写法)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> </head> <body> <!-- 准备好容器--> <div id="app"> {{message}} </div> </body> </html> <script> var vue = new Vue({ //el对象式 el:"#app", //data对象式 data:{ message:"princeHao" }, ///data函数式 data(){ return{ message:"princeHao" } } }); //el函数式 vue.$mount("#app") </script>
方法三(Vue3)
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <div id="app">{{ message }}</div> <script> const { createApp, ref } = Vue createApp({ setup() { const message = ref('Hello vue!') return { message } } }).mount('#app') </script>
注意:当一个容器对应多个Vue实例时,只有第一个Vue实例生效。即一个容器只对应一个Vue实例(一对一关系)
初识Vue:
- 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象:
- root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法:
- root容器里的代码被称为 【Vue校板】:
模范语法
插值表达式
最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):
<span>Message: {{ msg }}</span>
双大括号标签会被替换为相应组件实例中 msg 属性的值。同时每次 msg 属性更改时它也会同步更新。
Vue指令
Vue中的指令是Vue.js框架中一种特殊的功能,它们以v-
为前缀,用于在模板中声明性地绑定表达式到DOM元素上。Vue的指令为开发者提供了一种方便的方式来操作DOM和组件的响应式数据。以下是Vue中一些常见的指令及其说明:
注意事项
- 指令的优先级顺序:
v-cloak
>v-for
>v-if
>v-else-if
>v-else
>v-show
- 指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM上。
- 指令的表达式期望是单个JavaScript表达式(除了
v-for
)。
注意区分:js表达式和 js代码(语句)
1.表达式:一个表达式会产生一个值。可以放在任何一个需要值的地方:
- a
- a+b
- demo(1)
- x=y ? 'a': 'b'
- 2.js代码(语句)
- if(){}
- for(){}
1. 条件渲染指令
v-if
v-if
是 Vue.js 中一个非常有用的指令,用于根据表达式的真假值来条件性地渲染元素。
- 如果表达式的值为真(true),则元素会被渲染;
- 如果为假(false),则元素及其子元素在 DOM 中会被销毁。
这意味着当条件不满足时,
v-if
控制的元素不仅不会被显示,还会从 DOM 中完全移除,这有助于提高页面性能,因为不需要渲染那些不被使用的元素。<template> <div> <!-- 当 isVisible 为 true 时,此段落会显示 --> <p v-if="isVisible">现在你可以看到我。</p> </div> </template> <script> export default { data() { return { isVisible: true } } } </script>
注意事项
- 条件渲染:与
v-show
指令不同,v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。- 初始渲染:如果在初始渲染时条件为假,则元素和它的子组件将不会被创建或挂载。
- 切换开销:由于
v-if
条件不满足时元素会被销毁,所以它在切换条件时会有更高的开销。如果切换条件非常频繁,建议使用v-show
,因为它只是简单地切换元素的 CSS 属性display
。- 与
v-else
、v-else-if
一起使用:v-if
可以与v-else
、v-else-if
一起使用,以实现多个条件的渲染逻辑。<div v-if="type === 'A'">A</div> <div v-else-if="type === 'B'">B</div> <div v-else>Not A/B</div>
5. 在
<template>
标签中使用:有时你可能想基于条件渲染多个元素。由于v-if
只能用在单个元素(或组件)上,<template>
元素可以作为包装元素,并在其上使用v-if
。最终的渲染结果将不包含<template>
元素。<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>
v-show
在Vue中,
v-show
是一个指令,用于根据条件动态地切换元素的CSS属性display
。
- 当条件为真时,元素会被显示(
display: block
或其他对应的值,取决于元素的类型)- 当条件为假时,元素会被隐藏(
display: none
)。<template> <div> <button @click="toggle">Toggle</button> <p v-show="isVisible">Hello, Vue!</p> </div> </template> <script> export default { data() { return { isVisible: false } }, methods: { toggle() { this.isVisible = !this.isVisible; } } } </script>
v-show
与v-if
的主要区别在于,
v-if
是真正地条件性地渲染元素,意味着当条件为假时,元素及其所有的子节点都会被销毁并从DOM中移除,直到条件再次为真时,它们才会被重新创建并插入DOM中。- 而
v-show
仅仅是简单地切换元素的CSS属性display
,元素始终保留在DOM中,只是简单地切换其可见性。使用场景
- 频繁切换:如果你需要频繁地切换元素的显示状态,使用
v-show
会更合适,因为它避免了元素的销毁和重新创建,这样可以带来更好的性能。- 初始渲染:如果你希望元素在页面加载时就渲染到DOM中,即使它最初是隐藏的,那么
v-show
是一个好选择。而v-if
则会在条件为假时阻止元素的初始渲染。
2. 数据绑定指令
v-text
在Vue中,
v-text
是一个指令,用于更新元素的textContent
。当你需要将一个变量的值插入到HTML元素中时,v-text
是一个选择。不过,与{{ }}
插值表达式相比,v-text
会替换元素的全部内容,而不是只替换指定的占位符。使用场景
- 当你需要确保元素内的所有内容都被一个Vue变量的值替换时,
v-text
很有用。- 如果你不需要保留元素内除绑定值之外的其他HTML或文本内容,
v-text
是一个好选择。<template> <div> <!-- 使用插值表达式 --> <p>{{ message }}</p> <!-- 使用v-text指令 --> <p v-text="message"></p> </div> </template> <script> export default { data() { return { message: 'Hello, Vue!' } } } </script>
注意事项
- 使用
v-text
时,请确保你不会意外地删除元素中其他重要的内容。- 如果你需要在绑定值中包含HTML标签,则不应使用
v-text
,因为它会按纯文本处理。相反,你应该使用v-html
,但请注意,v-html
可能导致跨站脚本(XSS)攻击,因此在使用时要格外小心。- 在大多数情况下,
{{ }}
插值表达式足以满足你的需求,因为它既简单又灵活。但是,了解v-text
的用途和限制也是很有帮助的。
v-html
在Vue中,
v-html
是一个指令,用于输出真正的HTML内容。与v-text
不同,v-html
会替换元素的innerHTML
,允许你插入包含HTML标签的字符串。使用场景
- 当你需要渲染包含HTML标记的字符串时,
v-html
是必要的。- 但是,由于使用
v-html
可能会导致跨站脚本(XSS)攻击,因此它应该只在可信的内容上使用。<template> <div> <!-- 使用v-html指令渲染HTML内容 --> <div v-html="rawHtml"></div> </div> </template> <script> export default { data() { return { rawHtml: '<span style="color: red">This will be red.</span>' } } } </script>
注意事项
- XSS风险:使用
v-html
时,你正在将你的应用暴露于XSS攻击的风险之下。确保你完全信任要插入的HTML内容,或者对其进行了适当的清理和转义。- 性能考虑:在Vue中,使用
v-html
可能会导致性能问题,因为Vue无法追踪或优化innerHTML
中的DOM变化。如果可能的话,考虑使用Vue的组件系统来构建可复用的、可维护的UI部分。- 替代方案:在大多数情况下,你可以通过Vue的模板语法(如
{{ }}
插值表达式和条件/循环指令)来避免使用v-html
。只有当你需要渲染实际的HTML标签时,才应该考虑使用它。
v-pre
- 在Vue中,
v-pre
是一个特殊的指令,它的作用是指示Vue跳过该元素及其子元素的编译过程。这意味着Vue不会处理这些元素内部的Mustache标签(即双大括号{{ }}
包裹的表达式)或任何Vue指令(如v-if
、v-for
等)。- 这个指令通常用于显示原始的Mustache标签,或者当你想要Vue忽略某个元素内部的模板语法时非常有用。例如,你可能想要显示Vue模板的源代码,或者你可能在开发过程中暂时想要禁用某个元素的Vue功能。
使用场景
显示原始Mustache标签:当你想要在页面上直接显示
{{ message }}
这样的文本,而不是将其解析为Vue实例中的数据时。性能优化:对于大量静态内容的元素,使用
v-pre
可以跳过Vue的编译过程,从而提高性能。但是,请注意,这通常不是性能瓶颈的主要来源,除非你的页面包含大量的静态内容并且频繁地重新渲染。调试:在开发过程中,你可能想要暂时禁用某个元素的Vue功能,以便检查或调试页面的其他部分。
<div v-pre> {{ 这个文本不会被Vue解析 }} <!-- 这里的v-if指令也不会被Vue处理 --> <p v-if="false">这个段落不会显示</p> </div> <div> {{ 这个文本会被Vue解析为实例中的数据 }} </div>
注意
v-pre
指令主要用于开发过程中,在生产环境中,你应该确保Vue模板被正确编译。- 如果你想要在生产环境中跳过某些元素的编译,可能需要考虑其他方法,如使用条件渲染指令(如
v-if
)来控制元素的渲染,或者通过CSS来隐藏不需要的元素。但是,请注意,这些方法可能会引入额外的性能开销。
v-cloak
- 在Vue中,
v-cloak
是一个特殊的指令,它主要用于在Vue实例完全编译完成之前隐藏元素的原始Mustache标签(即双大括号{{ }}
包裹的表达式)。这是因为,在Vue实例开始编译并替换模板中的Mustache标签之前,这些标签会短暂地显示在页面上,这可能会导致用户看到未渲染的标记。- 为了解决这个问题,Vue提供了
v-cloak
指令。当Vue实例正在编译时,v-cloak
指令会保持在其元素上,并且你可以通过CSS来隐藏带有v-cloak
属性的元素。一旦Vue实例编译完成,v-cloak
属性会被自动移除,这时你就可以通过CSS来显示元素了。使用方法
在你的Vue模板中,为需要隐藏的元素添加
v-cloak
指令。在你的CSS中,添加一个规则来隐藏带有
v-cloak
属性的元素。示例
<div id="app" v-cloak> {{ message }} </div>
[v-cloak] { display: none; }
在这个示例中,当Vue实例开始编译时,
div
元素上的v-cloak
属性会保持在那里,并且由于CSS规则的作用,这个div
元素会被隐藏。一旦Vue实例编译完成,v-cloak
属性会被移除,这时div
元素就会显示出来,并且其中的{{ message }}
会被替换为Vue实例中message
属性的值。注意事项
v-cloak
指令主要用于解决Vue实例编译过程中可能出现的Mustache标签闪烁问题。- 它应该与CSS一起使用,以确保在编译完成之前元素是隐藏的。
- 一旦Vue实例编译完成,
v-cloak
属性就会被移除,这时你可以通过CSS来控制元素的显示样式。- 在大多数情况下,Vue的编译过程是非常快的,所以
v-cloak
主要用于开发过程中,以确保用户体验的流畅性。在生产环境中,这个问题通常不会那么明显。
v-once
在Vue中,
v-once
是一个指令,它的作用是将元素和组件只渲染一次。这意味着一旦元素或组件被渲染,Vue将不会再次对其进行更新,即使数据发生变化也是如此。这个指令主要用于优化性能,特别是对于那些不需要响应数据变化而重新渲染的元素。使用方法
- 你可以在模板中的任何元素或组件上使用
v-once
指令。当Vue遇到这个指令时,它会立即渲染该元素或组件,并忽略后续的数据变化。<template> <div> <!-- 这个p元素将只渲染一次,即使message的值在后续发生变化 --> <p v-once>{{ message }}</p> <!-- 这个p元素会响应message的变化而更新 --> <p>{{ message }}</p> </div> </template> <script> export default { data() { return { message: 'Hello, Vue!' } }, mounted() { // 假设这里有一个异步操作,操作完成后更新了message的值 setTimeout(() => { this.message = 'Hello, Vue again!'; }, 1000); } } </script>
在上面的示例中,第一个
<p>
元素使用了v-once
指令,所以它的内容只会在页面加载时渲染一次,即使message
的值在后续的mounted
钩子中被更新,这个<p>
元素的内容也不会改变。而第二个<p>
元素则会响应message
的变化,当message
的值更新时,它的内容也会相应地更新。注意事项
v-once
指令通常用于那些不需要响应数据变化的静态内容,以优化性能。- 如果你在组件上使用
v-once
,那么该组件及其所有子组件都只会渲染一次。- 需要注意的是,
v-once
指令不会阻止组件的初始渲染,它只是在组件渲染之后阻止其响应后续的数据变化。- 在大多数情况下,Vue的响应式系统和虚拟DOM算法已经足够高效,所以
v-once
的使用场景相对有限。然而,在渲染大量静态内容时,使用v-once
可以显著提高性能。
3. 类与样式绑定指令
v-bind
在Vue中,
v-bind
是一个指令,用于响应式地更新HTML属性。它可以简写为冒号(:
)。当你需要将Vue实例中的数据绑定到元素的属性上时,v-bind
是非常有用的。使用场景
- 当你需要根据Vue实例中的数据动态地改变HTML元素的属性时,比如
id
、class
、style
、href
等。- 它使得数据绑定到DOM属性变得既简洁又高效。
<template> <div> <!-- 使用v-bind绑定class --> <p v-bind:class="{'active': isActive}">This is a paragraph.</p> <!-- 简写形式 --> <p :class="{'active': isActive}">This is another paragraph.</p> <!-- 使用v-bind绑定href --> <a v-bind:href="url">Go to Vue.js</a> <!-- 简写形式 --> <a :href="url">Go to Vue.js (shorthand)</a> </div> </template> <script> export default { data() { return { isActive: true, url: 'https://vuejs.org' } } } </script>
注意事项
- 使用
v-bind
时,Vue会监听数据的变化,并在数据变化时自动更新DOM属性。- 除了标准的HTML属性外,
v-bind
还可以用于绑定Vue特有的指令,如v-model
(尽管v-model
是一个特殊的双向绑定指令,但在某些情况下它可以被看作是一个特殊的v-bind
)。- 在大多数情况下,使用
v-bind
的简写形式(即冒号)更为常见和方便。- 需要注意的是,当使用
v-bind
绑定到class
和style
时,Vue提供了额外的语法糖来支持更复杂的绑定场景,如对象语法和数组语法。
4. 表单输入绑定指令
v-model
在Vue中,
v-model
是一个指令,用于在表单输入和应用状态之间创建双向数据绑定。这意味着当输入字段的值发生变化时,绑定的数据也会更新,反之亦然。使用场景
v-model
主要用于表单输入,如input
、textarea
和select
元素。- 它简化了表单数据和Vue实例数据之间的同步过程。
工作原理
v-model
实际上是语法糖,它背后默认会利用元素的value
属性和input
事件来更新数据。但在一些特殊情况下(如复选框和单选按钮),v-model
会智能地切换为使用checked
属性并监听change
事件。<template> <div> <!-- 单行文本输入 --> <input v-model="message" placeholder="Edit me"> <p>Message is: {{ message }}</p> <!-- 多行文本输入 --> <textarea v-model="multiLineText"></textarea> <p>Multiline text is: {{ multiLineText }}</p> <!-- 下拉选择 --> <select v-model="selected"> <option disabled value="">Please select one</option> <option>A</option> <option>B</option> <option>C</option> </select> <p>Selected: {{ selected }}</p> </div> </template> <script> export default { data() { return { message: '', multiLineText: '', selected: '' } } } </script>
注意事项
- 虽然
v-model
在大多数情况下都很有用,但在某些复杂的表单场景中,你可能需要直接使用v-bind
和事件监听器(如v-on:input
)来实现更细粒度的控制。v-model
在Vue 3的Composition API中有所不同,因为它不再直接依赖于Vue实例的data
属性。相反,你可以使用ref
或reactive
来创建响应式数据,并使用v-model
的.sync
修饰符或自定义v-model
来实现双向绑定。但是,在Vue 3的Options API中,v-model
的使用方式与Vue 2相同。
5. 列表渲染指令
v-for
在Vue中,
v-for
是一个指令,用于基于一个数组来渲染一个列表。它可以使用数组中的索引和值来为每个元素渲染出一个模板。这使得在Vue中渲染列表变得非常简单和高效。使用场景
当你需要渲染一个列表或一组元素,并且这些元素是基于一个数组或对象时,
v-for
是非常有用的。- 它可以用于渲染
<ul>
、<ol>
、<table>
等HTML集合元素,也可以用于渲染任何一组元素。语法
- 对于数组:
<div v-for="(item, index) in items" :key="index"> {{ index }}: {{ item.text }} </div>
- 或者,如果你不需要索引:
<div v-for="item in items" :key="item.id"> {{ item.text }} </div>
- 对于对象:
<div v-for="(value, name, index) in object" :key="index"> {{ index }}. {{ name }}: {{ value }} </div>
但请注意,在对象上使用
v-for
时,第三个参数是键名(key)的索引,而不是值的索引,且它只在某些浏览器(如非IE11)中支持。<template> <ul> <li v-for="(todo, index) in todos" :key="todo.id"> {{ todo.text }} </li> </ul> </template> <script> export default { data() { return { todos: [ { id: 1, text: 'Learn JavaScript' }, { id: 2, text: 'Learn Vue' }, { id: 3, text: 'Build something awesome' } ] } } } </script>
注意事项
- 在使用
v-for
时,你应该始终为渲染的每个元素指定一个唯一的key
属性。这有助于Vue跟踪每个节点的身份,从而重用和重新排序现有元素,而不是每次都重新渲染整个列表。key
应该是一个唯一的字符串或数字,最好是每个元素的ID或唯一标识符。- 如果你只是简单地遍历一个整数范围,可以使用
v-for
与v-if
结合来渲染一个数字列表,但更常见的是使用计算属性或方法来生成这个范围。- 在Vue 2.x中,
v-for
的优先级高于v-if
。这意味着v-if
将分别应用于由v-for
创建的每个元素。在Vue 3.x中,这个行为可能有所不同,但通常推荐的做法是始终使用v-if
来控制是否应该渲染v-for
。
6. 事件处理指令
v-on
在Vue中,
v-on
是一个指令,用于监听DOM事件,并在触发时执行一些JavaScript代码。它是Vue处理事件的一种方式,允许你将JavaScript方法绑定到Vue模板中的DOM元素上。使用场景
- 当你需要在用户与页面上的元素交互(如点击、输入、键盘事件等)时执行某些操作时,
v-on
非常有用。语法
v-on
可以简写为@
符号,这是Vue提供的语法糖,使得代码更加简洁。
- 完整写法:
v-on:click="methodName"
- 简写形式:
@click="methodName"
参数
- 事件名:如
click
、input
、mouseover
等,表示要监听的事件类型。- 方法名:当事件发生时,Vue会调用这个方法来处理事件。这个方法应该在Vue实例的
methods
选项中定义。<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> </head> <body> <div> <!-- 完整写法 --> <button v-on:click="greet">点击我</button> <!-- 简写形式 --> <button @click="greet">点击我</button> <!-- 传递事件对象 --> <button @click="greetWithEvent($event)">点击我并传递事件对象</button> <button @click="greetWithEvent2()">点击我并传递事件对象2</button> <button @click="greetWithEvent2">点击我并传递事件对象2</button> <button @click="greetWithEvent3($event,10)">点击我并传递事件对象3</button> </div> <script> new Vue({ el:'div', methods: { greet() { alert('Hello, Vue!'); }, greetWithEvent(event) { // 这里可以访问到原生DOM事件对象 alert(event.type); }, greetWithEvent2() { alert(event.target); }, greetWithEvent3(event,a) { alert(event.target+' '+a); }, } }) </script> </body> </html>
注意事项
- 当使用
v-on
监听原生DOM事件时,Vue会将方法调用包装在一个.prevent
修饰符、.stop
修饰符等可用的修饰符之后,以便你能够阻止默认行为或停止事件冒泡。- 虽然
$event
是Vue的特殊变量,用于在方法参数中接收原始DOM事件对象,但在许多情况下,你可能不需要它。Vue鼓励你尽可能使用数据和方法来抽象DOM操作,而不是直接依赖DOM事件。- 你可以监听几乎所有的DOM事件,包括自定义事件。Vue组件之间经常通过自定义事件进行通信。
7. 自定义指令
在Vue中,自定义指令是一种强大的功能,它允许你封装DOM操作的逻辑,使得你的组件更加模块化和可重用。自定义指令通过Vue.directive()方法全局注册,或者通过组件的directives选项局部注册。
全局注册
- 使用
Vue.directive(id, [definition])
方法全局注册一个自定义指令,其中id
是自定义指令的名字(不包括v-
前缀),definition
是一个对象,它包含几个钩子函数(如bind
、inserted
、update
、componentUpdated
、unbind
)。Vue.directive('focus', { // 当被绑定的元素插入到DOM中时…… inserted: function (el) { // 聚焦元素 el.focus() } })
局部注册
- 在组件中,你可以通过
directives
选项来局部注册自定义指令。export default { directives: { focus: { // 指令的定义 inserted: function (el) { el.focus() } } } }
钩子函数
自定义指令的钩子函数有:
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用 (保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。
- componentUpdated:指令所在组件的VNode及其子VNode全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
钩子函数的参数
钩子函数被调用时,会传入以下参数:
- el:指令所绑定的元素,可以用来直接操作DOM。
- binding:一个对象,包含以下属性:
name
:指令名,不包括v-
前缀。value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为2
。oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否变化都可用。expression
:字符串形式的指令表达式。例如v-my-directive="1 + 1"
中,表达式为"1 + 1"
。arg
:传给指令的参数,可选。例如v-my-directive:foo
中,参数为"foo"
。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为{ foo: true, bar: true }
。- vnode:Vue编译生成的虚拟节点。
- oldVnode:上一个虚拟节点,仅在
update
和componentUpdated
钩子中可用。Vue.directive('change-color', { bind(el, binding) { el.style.cursor = 'pointer'; el.onclick = () => { el.style.color = binding.value; } } }) // 使用 <div v-change-color="'red'">点击我改变颜色</div>
Vue的属性
Vue中的属性众多,但核心和常用的属性主要包括以下几个方面:
1. el属性
- 功能:用来指示Vue编译器从什么地方开始解析Vue的语法,可以看作是一个占位符。
- 用法:在创建Vue实例时,通过
el
属性指定一个DOM元素,Vue将接管该元素及其内部的所有内容。
2. data属性
- 功能:用来组织从视图中抽象出来的数据,即将视图的数据抽象出来存放在
data
中。- 用法:在Vue实例中,
data
属性通常是一个对象,包含了需要响应式管理的数据。
3. methods属性
- 功能:用来放置页面中的业务逻辑,JavaScript方法一般都放置在
methods
中。- 用法:
methods
属性是一个对象,包含了多个方法,这些方法可以在模板中通过表达式或指令来调用。
4. computed属性
- 功能:计算属性,基于它们的依赖进行缓存。只有当依赖发生变化时,计算属性才会重新求值。
- 用法:在Vue实例中,通过
computed
属性定义函数,这些函数将作为计算属性被缓存,并可以直接在模板中作为普通数据使用。
5. watch属性
- 功能:侦听器,允许你对Vue实例上的数据变化进行响应。
- 用法:
watch
属性是一个对象,其中可以包含多个键值对,键是需要侦听的属性名,值是一个函数,该函数会在对应属性发生变化时被调用。
6. template属性
- 功能:用来设置模板,可以替换页面元素,包括
el
属性指定的占位符。- 用法:在Vue实例中,可以通过
template
属性来定义模板内容,这些模板内容将替换el
属性指定的DOM元素。
7. render属性
- 功能:渲染函数,用于创建真正的Virtual DOM。
- 用法:
render
属性是一个函数,它接收一个createElement
函数作为参数,并返回一个虚拟DOM节点。这个函数在Vue的底层实现中非常重要,但在实际开发中,通常不需要直接编写render
函数,而是通过模板或单文件组件的方式来编写Vue组件。
8. 其他常用属性或特性
- components:Vue实例配置局部注册组件的地方。
- filters:过滤器,用于对模板中的数据进行格式化。
- mixins:混入,允许将可复用的功能混入Vue组件中。
- 生命周期钩子:如
created
、mounted
、beforeDestroy
等,用于在Vue实例的不同生命周期阶段执行代码。
生命周期
Vue的生命周期是指Vue实例从创建到销毁的一系列过程。在这个过程中,Vue实例会经历多个阶段,每个阶段Vue都会调用一些生命周期钩子函数(也称为生命周期事件或生命周期回调),允许我们在不同阶段添加自己的代码,以实现特定的功能。
Vue 2.x 和 Vue 3.x 的生命周期钩子函数略有不同,但大体上可以分为以下几个阶段:
Vue 2.x 生命周期
- 创建前/后(初始化阶段):
- beforeCreate:在这个阶段,Vue实例被创建,但数据观测(data observer)、事件/侦听器的配置以及模板编译都尚未开始。此时,无法通过Vue实例访问到data中的数据、methods中的方法等。
- created:在这个阶段,实例创建已完成,数据观测(data observer)、属性和方法的运算、watch/event事件回调等配置都已就绪,但挂载阶段还没开始,$el属性目前不可见。此时,可以通过Vue实例访问到data中的数据、methods中的方法等,但页面呈现的是未经Vue编译的DOM结构,所有对DOM的操作最终都不奏效,因为都会被后续的页面渲染给覆盖掉。
- 挂载前/后(挂载阶段):
- beforeMount:在这个阶段,模板编译完成,但尚未挂载到页面上,此时页面呈现的是未经Vue编译的DOM结构。在这个阶段,可以发起服务端请求,去获取数据。
- mounted:在这个阶段,Vue实例被挂载到真实DOM节点上,此时页面呈现的是经过Vue编译的DOM结构,所有对DOM的操作均奏效,可以在此阶段进行一些初始化操作,如发送ajax请求、启动定时器、绑定自定义事件、订阅消息等。
- 更新前/后(更新阶段):
- beforeUpdate:在这个阶段,当Vue实例里面的data数据变化时,会触发组件的重新渲染,但此时页面尚未与数据保持同步,即页面尚未更新,但数据已经是最新的。
- updated:在这个阶段,页面与数据保持同步,即页面已经根据最新的数据进行了更新。
- 销毁前/后(销毁阶段):
- beforeDestroy:在这个阶段,Vue实例即将被销毁,此时实例仍然完全可用,可以手动销毁一些方法,如清除定时器、解绑自定义事件、取消订阅消息等。
- destroyed:在这个阶段,Vue实例已经被销毁,此时组件在浏览器中对应的DOM接口已被完全移除,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
Vue 3.x 生命周期
Vue 3.x 引入了 Composition API,但它仍然保留了 Options API,所以 Options API 的生命周期钩子与 Vue 2.x 相同。对于使用 Composition API 的情况,Vue 3.x 提供了
onXxx
形式的生命周期钩子函数,如onMounted
、onUpdated
、onBeforeUnmount
和onUnmounted
,它们分别对应于 Vue 2.x 中的mounted
、updated
、beforeDestroy
和destroyed
钩子。注意事项
- 在 Vue 3.x 中,
beforeDestroy
和destroyed
钩子被重命名为beforeUnmount
和unmounted
,以更好地反映它们的作用(即组件的卸载,而不是实例的销毁)。- 在使用 Composition API 时,生命周期钩子需要通过
import { onMounted, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
引入。- 生命周期钩子的使用可以帮助我们更好地控制组件的行为,例如,在组件创建时获取数据,在组件销毁时清理资源等
组件
在Vue中,组件是构建Vue应用的基本单位。一个组件可以视为一个拥有预定义选项的Vue实例,它可以包含模板、逻辑和样式封装,使得开发者能够复用代码、组织项目结构更加清晰。
大白话来说,组件就是页面!
使用步骤
- 定义组件(创建)
- 注册组件
- 局部注册:new Vue(components:{ 组件名 : 组件 })
- 全局注册:Vue.component('组件名',组件)
- 使用组件(写组件标签)
注意事项
- Vue.extend({option}) 其中 option 中的不能写 el 属性
- data 属性必须写成函数式
- 可以使用 template 配置组件结构
组件命名
- 建议组件每个单词首字母都大写
- 一个单词组成
- 第一种写法(首字母小写):school
- 第二种写法(首字母大写):School【推荐】
- 多个单词组成
- 第一种写法(kebab-case命名):my-school
- 第二种写法(CamelCase命名):MySchool(需要Vue脚手架支持)【推荐】
- 备注:
- 组件名尽可能回避HTML中已有的元素名称,例如:h1、H2都不行
- 可以使用name配置项指定组件在开发者工具中呈现的名字
多单词构成的组件名:例如 my-school 在注册组件的时候,必须用''包括起来
new Vue({ components:{ 'my-school':myschool } })
关于逐渐标签
- 第一种写法:<school></school>
- 第二中写法:<school/>
- 备注:不能使用脚手架时,<school/>会导致后续组件不能渲染
一个简写方式:
const school = Vue.entend(options) 可简写成:const school = options
非单文件组件
局部组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> </head> <body> <div id="app"> <!--第三步 使用组件标签 --> <school></school> <hr/> <student></student> <hr/> <h1>{{msg}}</h1> </div> </body> </html>
<script> // 第一步 创建组件 const school = Vue.extend({ template:` <!-- template 可以随意换行,不用写<br/>标签 --> <div> <h2>学校名字:{{schoolName}}</h2> <h2>学校地址:{{schoolAddress}}</h2> <button @click="showName">点我提示学校</button> </div> `, data(){ // 组件里面的data必须写出函数式,不能写成对象式 return{ schoolName:'和平大学', schoolAddress:'北京昌平' } }, methods:{ showName(){ alert(this.schoolName) } } }) const student = Vue.extend({ template:` <div> <h2>学生名字:{{stuname}}</h2> <h2>学生年龄:{{stuage}}</h2> </div> `, data(){ return{ stuname:'张三', stuage:18 } } }) new Vue({ el:'#app', data:{ // 此处可以写出对象形式或者函数式 msg:'hello world!' }, // 第二部 注册局部组件 components:{ student, school:school // 键值对同名,可省略以上形式 } }) </script>
全局组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> </head> <body> <div id="app"> <!--第三步 使用组件标签 --> <school></school> <hr/> <h1>{{msg}}</h1> </div> </body> </html>
<script> // 第一步 创建组件 const school = Vue.extend({ template:` <!-- template 可以随意换行,不用写<br/>标签 --> <div> <h2>学校名字:{{schoolName}}</h2> <h2>学校地址:{{schoolAddress}}</h2> <button @click="showName">点我提示学校</button> </div> `, data(){ // 组件里面的data必须写出函数式,不能写成对象式 return{ schoolName:'和平大学', schoolAddress:'北京昌平' } }, methods:{ showName(){ alert(this.schoolName) } } }) //第二步 注册全局组件 Vue.component('school',school) new Vue({ el:'#app', data:{ // 此处可以写出对象形式或者函数式 msg:'hello world!' } }) </script>
组件的嵌套
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> </head> <body> <div id="app"></div> </body> </html>
<script> // 子组件必须写在父组件之前申明,否则报错! const student = Vue.extend({ template:` <div> <h2>学生名字:{{stuname}}</h2> <h2>学生年龄:{{stuage}}</h2> </div>`, data(){ return{ stuname:'张三', stuage:18 } } }) const school = Vue.extend({ template:` <div> <h2>学校名字:{{schoolName}}</h2> <h2>学校地址:{{schoolAddress}}</h2> <hr> <student></student> <!-- 在父组件中写子组件的标签 --> </div>`, data(){ return{ schoolName:'和平大学', schoolAddress:'北京昌平' } }, components:{ student } }) const hello = Vue.extend({ template:` <div> <h2>{{Hi}}</h2> </div>`, data(){ return{ Hi:'hello world!' } } }) // 使用全局app管理所有组件 (标准写法) const app = { // 简写,省略Vue.extend() template:` <div> <hello></hello> <school></school> </div>`, components:{hello,school} } new Vue({ template:`<app></app>`, el:'#app', components:{app} }) </script>
模块与组件分离
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> </head> <body> <div id="app"> <abc></abc> </div> <!-- template 必须在容器外部定义 --> <template id="test"> <div> <h2>{{message}}</h2> </div> </template> </body> </html> <script> Vue.component('abc',{ template:'#test', data(){ return{ message:'hello wolrd!' } } }) new Vue({ el:'#app' }) </script>
VueComponent构造函数
关于VueComponent:
- school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
- 我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。
- 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!
- 关于this指向:
- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是 【VueComponent实例对象】。
- new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
- VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
Vue实例与组件实例
vc 有的,vm 都有;但 vm 有的,vc不一定有,例如 el 不能出现在 vc 里面
重要的内置关系
- 一个承要的内置关系: VueComnonent.prototype. __proto__ === Vue.prototype
- 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性,方法。
- 如何理解组件实例对象:它是一个小型的vm,但又不和vm完全一样,例如它的data只能写成函数式,不能含有 el 配置项
单文件组件
Vue单文件组件(Single-File Components,简称SFCs)是Vue.js官方推荐的一种组件编写方式,它允许我们将一个组件的模板(template)、脚本(script)、样式(style)封装在同一个
.vue
文件中。这种方式不仅提高了代码的可维护性,也使得组件之间的重用变得更加容易。Vue单文件组件主要由以下几个部分组成:
模板(template):定义了组件的HTML结构。Vue会将这部分的HTML编译成虚拟DOM,然后根据数据的变化来高效地更新视图。在
.vue
文件中,<template>
标签包裹的内容就是组件的模板。脚本(script):包含了组件的逻辑。在
<script>
标签内部,你可以定义组件的数据(data)、计算属性(computed)、方法(methods)、生命周期钩子(lifecycle hooks)等。这些JavaScript代码会运行在Vue实例的上下文中,可以访问到Vue实例的数据和方法。样式(style):定义了组件的样式。在
<style>
标签内部,你可以编写CSS代码来定义组件的样式。Vue单文件组件支持CSS的作用域,通过添加scoped
属性,你可以确保样式只作用于当前组件的根元素,避免样式冲突。可选的其他部分:虽然模板、脚本和样式是单文件组件的核心部分,但Vue单文件组件还支持其他的一些可选部分,如:
- 自定义块(Custom Blocks):
<template>
、<script>
、<style>
之外的任何标签都会被视为自定义块,你可以利用这些自定义块来集成第三方库(如预处理器、文档生成等)。- 混入(Mixins)、插件(Plugins)、指令(Directives)等Vue的高级特性也可以在单文件组件中使用,但通常这些不会直接体现在
.vue
文件的结构上,而是作为脚本部分的一部分被引入或定义。
三种暴露方式:
暴露一:分别暴露
引入格式:import {xxx} from xxx
暴露二:统一暴露 引入格式:import {xxx} from xxx
暴露三:默认暴露 引入格式:import xxx from xxx
最佳优化
Vue的传参
在Vue中,组件之间的传参是一个常见的需求,Vue提供了多种方式来实现这一功能。这些方式主要依赖于父子组件之间的关系以及是否跨组件层级。以下是一些常用的传参方式:
1. Props(父传子)
在Vue中,父组件向子组件传参是通过
props
(属性)来实现的。这是一种单向数据流的方式,即父组件可以向子组件传递数据,但子组件不能直接修改这些数据。如果子组件需要基于这些数据进行操作或修改,并希望将修改后的结果反馈给父组件,那么需要通过事件($emit
)或其他机制(如Vuex)来实现。父组件:
<template> <div> <h1>Parent Component</h1> <!-- 使用子组件,并通过:prop-name="parentData"的方式将parentData传递给子组件的propName属性 --> <ChildComponent :propName="parentData" /> </div> </template> <script> // 引入子组件 import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { // 父组件的数据 parentData: 'Hello from Parent' } } } </script>
子组件(ChildComponent.vue):
<template> <div> <h2>Child Component</h2> <!-- 显示从父组件接收到的数据 --> <p>{{ propName }}</p> </div> </template> <script> export default { // 使用props来声明一个名为propName的属性,这样父组件就可以向子组件传递数据到这个属性了 props: ['propName'], // 注意:在组件内部,props的值是只读的,不应该被直接修改 // 如果需要基于这些props的值进行计算或修改,并在父组件中使用,应该使用事件或其他状态管理方案 } </script>
在这个例子中,父组件通过
:propName="parentData"
(注意:
是v-bind
的简写,用于动态绑定属性)将parentData
的值传递给子组件的propName
属性。子组件通过声明props: ['propName']
来接收这个值,并在模板中使用{{ propName }}
来显示它。
2. Events(子传父)
在Vue中,子组件向父组件传递数据或消息通常是通过事件(Events)来实现的。子组件可以触发一个事件,并传递数据作为事件的参数,父组件则监听这个事件并处理接收到的数据。
子组件:
<template> <div> <button @click="sendMultipleDataToParent">Send Multiple Data to Parent</button> </div> </template> <script> export default { methods: { sendMultipleDataToParent() { // 使用$emit触发一个名为'update-parent-data'的事件,并传递多个参数 this.$emit('update-parent-data', 'Hello', 123, true); } } } </script>
父组件:
<template> <div> <h1>Parent Component</h1> <!-- 监听子组件触发的'update-parent-data'事件,并调用handleChildData方法处理数据 --> <ChildComponent @update-parent-data="handleChildData" /> <p>Received Data 1: {{ childData1 }}</p> <p>Received Data 2: {{ childData2 }}</p> <p>Received Data 3: {{ childData3 }}</p> </div> </template> <script> // 引入子组件 import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { // 用于存储从子组件接收到的数据 childData1: '', childData2: null, childData3: false } }, methods: { handleChildData(data1, data2, data3) { // 处理从子组件接收到的多个数据 this.childData1 = data1; this.childData2 = data2; this.childData3 = data3; } } } </script>
- 在这个例子中,子组件的
sendMultipleDataToParent
方法使用$emit
触发了update-parent-data
事件,并传递了三个参数:一个字符串'Hello'
,一个数字123
,和一个布尔值true
。- 父组件在模板中通过
<ChildComponent @update-parent-data="handleChildData" />
监听了这个事件,并指定了handleChildData
方法作为事件处理函数。当事件被触发时,handleChildData
方法会被调用,并且传递的三个参数(在这个例子中是'Hello'
、123
和true
)会被作为参数传入这个方法。然后,父组件可以将这些参数分别存储在本地状态(如childData1
、childData2
和childData3
)中,或者进行其他处理。
3. Vuex(状态管理)
对于跨组件的复杂通信,尤其是当多个组件需要共享状态时,Vuex是一个很好的选择。Vuex是一个专为Vue.js应用程序开发的状态管理模式+库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
安装Vuex(如果尚未安装):
npm install vuex --save # 或者 yarn add vuex
创建store并管理状态:
// store.js import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ state: { message: 'Hello from Vuex' }, mutations: { setMessage(state, newMessage) { state.message = newMessage; } } });
在Vue实例中使用store:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; new Vue({ store, render: h => h(App) }).$mount('#app');
在组件中访问和修改状态:
<template> <div>{{ $store.state.message }}</div> <button @click="changeMessage">Change Message</button> </template> <script> export default { methods: { changeMessage() { this.$store.commit('setMessage', 'New message'); } } } </script>
4. Provide / Inject(跨层级组件通信)
provide
和inject
选项主要用于高级插件/组件库的开发,但也可以用于实现跨多层的组件通信。provide
选项允许你指定你想要提供给后代组件的数据/方法,而inject
选项则允许一个后代组件接收这些数据/方法。祖先组件:
<script> export default { provide() { return { message: 'Hello from ancestor' } } } </script>
后代组件:
<script> export default { inject: ['message'], mounted() { console.log(this.message); // 输出: Hello from ancestor } } </script>
插槽
Vue中的插槽(Slots)是一种非常灵活的内容分发API,它允许我们定义组件的结构,并将组件的某些部分开放给使用者来定义。这使得组件更加通用和可重用。Vue 2.x 和 Vue 3.x 中都支持插槽,但在Vue 3.x中,插槽的语法和内部实现有所更新和优化。
Vue 2.x 中的插槽
在Vue 2.x中,插槽主要分为匿名插槽、具名插槽和作用域插槽。
- 匿名插槽:也称为默认插槽,是最简单的插槽形式。它不包含名称,父组件中所有不在
<template>
标签内指定slot
属性的内容都会被渲染到子组件的匿名插槽中。
- 子组件
<template> <div> <slot></slot> </div> </template>
- 父组件
<child> <p>这是传递给子组件的插槽内容</p> </child>
- 具名插槽:如果子组件中有多个插槽,可以通过
name
属性来区分它们。在父组件中,通过<template>
标签的slot
属性来指定要渲染到哪个插槽中。
- 子组件
<template> <div> <header> <slot name="header"></slot> </header> <main> <slot></slot> <!-- 匿名插槽 --> </main> <footer> <slot name="footer"></slot> </footer> </div> </template>
- 父组件
<child> <template slot="header"> <h1>标题</h1> </template> <p>这是匿名插槽的内容</p> <template slot="footer"> <p>页脚</p> </template> </child>
- 作用域插槽:允许子组件将数据传递给插槽的内容。在子组件的
<slot>
标签中,通过v-bind
绑定数据,父组件的插槽内容可以通过slot-scope
(在Vue 2.6.0+中推荐使用v-slot
)接收这些数据。
- 子组件
<template> <ul> <li v-for="item in items" :key="item.id"> <slot :item="item">{{ item.text }}</slot> </li> </ul> </template>
- 父组件
<child> <template v-slot:default="slotProps"> <span>{{ slotProps.item.text }}</span> </template> </child>
Vue 3.x 中的插槽
在Vue 3.x中,插槽的语法有所变化,但基本概念保持不变。主要的变化是废弃了
slot
和slot-scope
属性,转而使用v-slot
指令。具名插槽和作用域插槽在Vue 3.x中仍然支持,但使用
v-slot
指令代替了slot
和slot-scope
属性。
- 具名插槽
<child> <template v-slot:header> <h1>标题</h1> </template> </child>
- 作用域插槽
<child> <template v-slot:default="{ item }"> <span>{{ item.text }}</span> </template> </child>
或者,使用
#
作为v-slot:
的简写:<child> <template #header> <h1>标题</h1> </template> <template #default="{ item }"> <span>{{ item.text }}</span> </template> </child>
脚手架 CLI
采用taobao的镜像地址,进入cmd之后输入:
npm config set registry https://registry.npm.taobao.org