一: Vue 初阶
1.1 关于不同版本的 Vue
Vue.js 有不同版本,如 vue.js
与 vue.runtime.xxx.js
,这些版本主要针对不同的使用场景和需求进行了优化,区别主要体现在以下几个方面:
-
完整版 vs 运行时版:
vue.js
(完整版):这是包含编译器的完整构建版本。它包括 Vue 的 template 模板编译器,可以将 Vue 模板直接编译成渲染函数。因此,它适用于独立运行的 Vue.js 项目或通过<script>
引入的方式直接使用。vue.runtime.xxx.js
(运行时版):这是不包含模板编译器的版本,体积更小。它假设你使用了其他构建步骤来预编译模板,或者通过 Vue 的单文件组件 (SFC) 来开发。这种版本需要配合使用 webpack 或其他构建工具进行构建。
-
适用场景:
- 完整版适用于传统的 Vue.js 项目,特别是对于通过
<script>
标签直接引入 Vue 的项目。它包含了模板编译器,因此可以接受字符串模板,而不需要预编译。 - 运行时版更适合基于构建系统(如 Vue CLI、webpack 等)的项目,其中模板是预编译的,因此不需要 Vue 自带的编译器,可以减小项目体积并提高运行效率。
- 完整版适用于传统的 Vue.js 项目,特别是对于通过
-
为什么要分这么多版本:
- 灵活性和体积优化:Vue.js 为了提供更多的灵活性和优化体积,将模板编译器与运行时分离。对于大型项目或需要性能优化的项目,可以选择运行时版本,并预先编译模板,以减小包大小和提高加载速度。
- 开发体验:对于单文件组件(SFC)的开发,使用运行时版本可以更好地配合现代构建工具(如 webpack)进行开发和部署,更符合当前前端开发的最佳实践。
1.2 asserts 文件夹
在前端项目中,asserts
文件夹通常用来存放静态资源文件,些资源文件包括但不限于:
- 图像文件:如
.jpg
,.png
,.gif
等格式的图片文件,用于网站的图像展示、背景等。 - 样式表文件:如
.css
,.scss
,.less
等格式的样式表文件,用于定义网站的样式和布局。 - 字体文件:如
.ttf
,.woff
,.woff2
等格式的字体文件,用于网站的文字排版。 - JavaScript 文件:如
.js
格式的 JavaScript 脚本文件,用于网站的交互逻辑和功能实现。 - 视频文件:如
.mp4
,.avi
,.mov
等格式的视频文件,用于网站的视频展示或背景视频。 - 音频文件:如
.mp3
,.ogg
,.wav
等格式的音频文件,用于网站的音频播放或背景音乐。 - 其他静态文件:如
.html
,.xml
,.json
等格式的文件,用于网站的其他静态内容。
这些静态资源文件通常在开发中需要被引用和加载到网页中,因此将它们放在 asserts
文件夹中,便于管理和组织。
1.3 components 文件夹
在前端开发中,components
文件夹通常用来存放 Vue.js 应用中的组件文件,将所有组件集中存放在一个文件夹下,可以使得项目结构更加清晰,开发者可以快速找到需要的组件文件。
除了常见的 App.vue
组件外,components
文件夹中可能还会包含其他各种功能性和业务相关的组件,例如:
- Header.vue:顶部导航栏组件。
- Footer.vue:底部版权信息组件。
- Sidebar.vue:侧边栏组件。
- Button.vue:自定义按钮组件。
- Modal.vue:弹窗组件。
- 等等。
每个组件都有其特定的功能和作用,通过组合这些组件,可以构建出复杂的用户界面。而 App.vue
则是 Vue.js 应用的根组件,负责整个应用的布局和路由管理,通常会包含其他子组件来组成完整的页面结构。
1.4 render 函数
render
函数有模板解析器,可以用来渲染虚拟 DOM 的函数。通过 render
函数,我们可以直接利用 JavaScript 来描述组件的 UI 布局和结构,而不是依赖于模板语法。
下面是关于render
函数的详细解析:
参数:
render
函数接受一个参数,通常命名为 h
,这个参数实际上是 createElement
函数的别名,用于创建 VNode(虚拟节点)。
注意点:
- 返回值:
render
函数必须返回一个 VNode,用于描述组件的 UI 结构。 - 单一根节点:
render
函数中返回的 VNode 必须是一个单一的根节点,即只能返回一个 VNode。 - 箭头函数:通常
render
函数使用箭头函数来定义,以确保函数内部的this
指向正确。
createElement 的用法:
createElement
函数用于创建 VNode(虚拟节点),描述组件的 UI 结构。它接受三个参数:
- 参数1(必填):标签名、组件选项或者一个返回组件选项的函数。
- 参数2(可选):一个包含组件属性和数据的对象,也可以是
null
。 - 参数3(可选):子节点,可以是一个数组或者一个字符串。
createElement
的用法通常如下:
h(tag, data, children)
其中:
tag
:可以是 HTML 标签名,也可以是组件选项。data
:是一个对象,包含了组件的属性和数据。children
:是一个数组,包含了组件的子节点。
例如,一个简单的 createElement
的用法如下:
h('div', { class: 'container' }, [
h('h1', 'Hello, Vue!'),
h('p', 'This is a paragraph.')
])
这段代码会创建一个 <div>
元素,其类名为 container
,包含一个 <h1>
元素和一个 <p>
元素作为子节点。
render 函数简写过程:
//完整版
render(createdElment){
return createdElment('h1','你好啊')
}
//第一步
render:(createdElment)=>{
return createdElment('h1','你好啊')
}
//第二步
render:createdElment=> createdElment('h1','你好啊')
//第三步
render:h=> h('h1','你好啊')
1.5 ref 属性
ref
是 Vue.js 中用来在模板中获取对 DOM 元素或组件实例的引用的属性。它的作用十分重要,能够让我们在 Vue 组件中直接操作 DOM,或者获取到子组件的实例,从而实现一些特定的逻辑或操作。
下面我来详细解释 ref
的作用:
作用:
-
获取 DOM 元素引用:通过在模板中使用
ref
,可以获取到对应 DOM 元素的引用,从而在 Vue 组件中直接操作该 DOM 元素。 -
获取组件实例引用:除了获取 DOM 元素的引用,
ref
还可以获取到子组件的实例引用,使得我们可以直接调用子组件的方法或访问其属性。 -
动态引用:
ref
属性可以动态地绑定到数据属性上,使得我们可以根据条件或状态动态地获取对应的 DOM 元素或组件实例。
代码示例:
获取 DOM 元素引用:
<template>
<div>
<button ref="myButton" @click="handleClick">Click me</button>
</div>
</template>
<script>
export default {
methods: {
handleClick() {
// 使用 $refs 来获取 DOM 元素引用,并直接操作该 DOM 元素
this.$refs.myButton.innerText = 'Button Clicked';
}
}
}
</script>
在这个示例中,ref="myButton"
将按钮元素的引用保存在了 myButton
中,然后在 handleClick
方法中,通过 this.$refs.myButton
获取到按钮元素的引用,并修改了按钮的文本内容。
获取子组件实例引用:
<template>
<div>
<!-- 使用 ref 获取子组件实例 -->
<child-component ref="myChild"></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
mounted() {
// 使用 $refs 获取子组件实例,并调用子组件的方法
this.$refs.myChild.sayHello();
}
}
</script>
在这个示例中,通过 ref="myChild"
获取了子组件 ChildComponent
的实例引用,然后在 mounted
钩子函数中,通过 this.$refs.myChild
获取到了子组件的实例,并调用了子组件的 sayHello
方法。
动态引用:
<template>
<div>
<div v-if="showRef">
<input ref="inputField" type="text" placeholder="Enter something" />
</div>
<button @click="toggleRef">Toggle Ref</button>
</div>
</template>
<script>
export default {
data() {
return {
showRef: true
};
},
methods: {
toggleRef() {
// 动态修改 showRef 的值,控制是否显示 ref
this.showRef = !this.showRef;
// 在输入框显示时,获取输入框的引用并聚焦
if (this.showRef) {
this.$refs.inputField.focus();
}
}
}
}
</script>
在这个示例中,通过 v-if
控制了一个输入框的显示与隐藏,当点击按钮时,通过 toggleRef
方法动态地切换输入框的显示状态。当输入框显示时,使用 this.$refs.inputField.focus()
获取输入框的引用并使其获得焦点。
1.6 props 配置
在 Vue.js 中,props
是用于父组件向子组件传递数据的一种机制。通过在子组件上声明 props
,可以将父组件中的数据传递给子组件,在子组件内部可以像访问本地数据一样使用这些 props。这种数据流的方式使得组件之间的通信更加灵活和维护。
下面我来详细解释 props
的用途以及如何在 Vue.js 中使用:
用途:
- 传递数据:最常见的用途是在父组件中将数据传递给子组件,子组件可以通过
props
接收这些数据并在内部使用。 - 向子组件传递事件:除了数据之外,父组件还可以通过props` 向子组件传递方法,以便子组件可以调用这些方法来实现特定的行为或逻辑。
代码示例:
1. 父组件向子组件传递数据:
<!-- ParentComponent.vue(父组件) -->
<template>
<div>
<!-- 在子组件上使用 props将 message 数据传递给子组件 -->
<ChildComponent :message="messageFromParent" </div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
messageFromParent: 'Hello from parent component'
};
}
}
</script>
<!-- ChildComponent.vue(子组件) -->
<template>
<div>
<!-- 在子组件中使用 props 接收来自父组件的数据 -->
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
props: {
// 声明 props,接收来自父组件的 message 数据
message: String
}
}
</script>
在这个示例中,父组件 ParentComponent
中的 messageFromParent
数据通过 message
props 传递给了子组件 ChildComponent
,子组件内部使用 props
来接收父组件传递的数据,并渲染到页面上。
父组件向子组件传递方法:
<!-- ParentComponent.vue(父组件) -->
<template>
<div>
<!-- 在子组件上使用 props,将父组件的方法传递给子组件 -->
<ChildComponent :handleClick="handleClickFromParent" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleClickFromParent() {
console.log('Button clicked in parent component');
}
}
}
</script>
<!-- ChildComponent.vue(子组件) -->
<template>
<div>
<!-- 在子组件中使用 props 接收来自父组件的方法 -->
<button @click="handleClick">Click me</button>
</div>
</template>
<script>
export default {
props: {
// 声明 props,接收来自父组件的方法
handleClick: Function
},
methods: {
handleClick() {
// 在子组件中调用父组件传递的方法
this.handleClick();
}
}
}
</script>
在这个示例中,父组件 ParentComponent
中的 handleClickFromParent
方法通过 handleClick
props 传递给了子组件 ChildComponent
,子组件内部使用 props
来接收父组件传递的方法,并在按钮点击时调用该方法。
1.6.1 子组件向父组件传递数据
在 Vue.js 中,通过 props
和父组件预先定义的方法,可以使子组件向父组件传递数据。这个过程涉及了子组件调用父组件传递的函数,并将数据作为参数传递回父组件的过程。
实现子组件向父组件传递数据的步骤:
-
在父组件中定义方法并将其传递给子组件:首先,在父组件中定义一个方法,并将这个方法通过
props
传递给子组件。 -
子组件调用父组件传递的方法:在子组件中调用从父组件接收到的方法,并传递数据作为参数。
代码示例:
父组件定义方法并传递给子组件:
<!-- ParentComponent.vue(父组件) -->
<template>
<div>
<!-- 将父组件的方法传递给子组件 -->
<ChildComponent :sendDataToParent="sendDataToParent" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
// 定义父组件的方法
sendDataToParent(data) {
console.log('Data received in parent:', data);
// 这里可以对数据进行处理或进一步操作
}
}
}
</script>
子组件调用父组件传递的方法并传递数据:
<!-- ChildComponent.vue(子组件) -->
<template>
<div>
<button @click="sendDataToParent">Send Data to Parent</button>
</div>
</template>
<script>
export default {
props: {
// 声明接收父组件传递的方法
sendDataToParent: Function
},
methods: {
sendDataToParent() {
const data = 'Data from child component';
// 调用父组件传递过来的方法,并传递数据
this.sendDataToParent(data);
}
}
}
</script>
在这个示例中,父组件 ParentComponent
定义了一个名为 sendDataToParent
的方法,并将这个方法通过 props
传递给子组件 ChildComponent
。在子组件中,当按钮被点击时,sendDataToParent
方法会被调用,并向父组件传递数据 'Data from child component'
。
这样,子组件就可以通过调用父组件预先定义的方法,向父组件传递数据。父组件可以在接收到数据后执行相应的逻辑或处理操作,实现了子组件向父组件的数据传递。
1.7 mixin 混入
在 Vue.js 中,mixin
是一种重用组件选项的一种方式。它允许我们定义一些可复用的组件选项,并在多个组件中共享这些选项。
mixin
可以包含组件选项,如数据、计算属性、方法、生命周期钩子等,通过混入 mixin
,这些选项会被合并到组件的选项中,从而实现了代码的复用和组件的扩展。
下面我来详细解释 mixin
的用途以及如何在 Vue.js 中使用:
用途:
-
代码复用:
mixin
允许我们将一些通用的逻辑或功能抽离出来,定义在mixin
中,然后在多个组件中重用这些逻辑或功能,避免代码重复,提高代码的可维护性和可读性。 -
逻辑组织:通过
mixin
,我们可以将组件选项按照功能进行拆分和组织,使得代码结构更加清晰和易于管理。 -
动态修改组件选项:在一些特定场景下,我们可以动态地为组件添加或修改选项,这使得
mixin
具有一定的灵活性,可以根据需要动态地调整组件的行为。
代码示例:
创建一个 mixin:
// exampleMixin.js
export const exampleMixin = {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
},
decrement() {
this.count--;
}
}
};
在这个示例中,我们创建了一个名为 exampleMixin
的 mixin,其中包含了一个名为 count
的数据属性和两个方法 increment
和 decrement
。
在组件中使用 mixin:
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script>
import { exampleMixin } from './exampleMixin.js';
export default {
mixins: [exampleMixin], // 使用 mixin
};
</script>
在这个示例中,我们在一个 Vue 组件中使用了 exampleMixin
,通过在组件选项中的 mixins
数组中添加 exampleMixin
,该 mixin 中的数据和方法会被合并到组件的选项中,从而实现了代码的复用。
动态修改组件选项:
// exampleMixin.js
export const exampleMixin = {
data() {
return {
message: 'Hello from mixin'
};
},
created() {
console.log('Mixin created');
}
};
// 在组件中动态添加 mixin
Vue.mixin(exampleMixin);
在这个示例中,我们在 exampleMixin
中定义了一个 message
数据属性和一个 created
生命周期钩子。然后通过 Vue.mixin
方法将 exampleMixin
动态地添加到全局的 Vue 实例中,这样在任何组件中都可以使用 exampleMixin
中的选项了。
1.8 scoped 样式
在 Vue.js 中,scoped
是一个用于样式作用域控制的特殊属性,它可以限定样式只在当前组件中生效,而不会影响到其他组件。这种机制可以避免全局样式污染和样式冲突,使得组件化开发更加可靠和可维护。
下面我来详细解释 scoped
的用途以及如何在 Vue.js 中使用:
用途:
-
避免样式污染:通过
scoped
属性,可以确保当前组件中的样式只作用于当前组件,不会影响到全局的样式,避免了样式污染问题。 -
组件化开发:
scoped
样式使得组件更加独立和可移植,组件可以被放置在任何上下文中而不会产生样式冲突,从而实现了更高程度的组件化开发。 -
提高样式可维护性:将样式与组件紧密绑定在一起,可以使得样式与组件的关系更加清晰,提高了样式的可维护性和可读性。
代码示例:
使用 scoped 属性定义样式:
<template>
<div class="example">
<p>This is a scoped example component.</p>
</div>
</template>
<script>
export default {
name: 'ExampleComponent'
}
</script>
<style scoped>
.example {
background-color: #f0f0f0;
padding: 20px;
}
p {
color: blue;
}
</style>
在这个示例中,我们定义了一个名为 ExampleComponent
的 Vue 组件,并使用 scoped
属性定义了组件的样式。样式中的 .example
类和 p
元素的样式只会作用于当前组件,不会影响到其他组件。