Vue 3是一个用于构建用户界面的JavaScript框架,它具有一套生命周期钩子函数,用于在Vue实例的不同阶段执行特定的操作。
beforeCreate:在Vue实例被创建之前被调用。在该阶段,Vue实例的数据和事件都没有初始化。
created:在Vue实例被创建之后立即被调用。在该阶段,Vue实例已经完成了数据观测、属性和方法的运算,但是尚未挂载到DOM中。
beforeMount:在Vue实例被挂载到DOM之前被调用。在该阶段,模板编译已经完成,但是尚未替换真实DOM。
mounted:在Vue实例被挂载到DOM之后被调用。在该阶段,Vue实例已经被挂载到真实DOM中,可以访问到DOM对象。
beforeUpdate:在数据更新之前被调用。在该阶段,Vue实例的数据已经发生了改变,但是DOM还没有被重新渲染。
updated:在数据更新之后被调用。在该阶段,Vue实例的数据已经发生了改变,并且DOM已经被重新渲染。
beforeUnmount:在Vue实例被销毁之前被调用。在该阶段,Vue实例尚未被销毁,但是DOM已经被移除。
unmounted:在Vue实例被销毁之后被调用。在该阶段,Vue实例已经被销毁,不再可用。
除了上述生命周期钩子函数,Vue 3还引入了一些新的特性,如setup函数和追踪响应式依赖。setup函数在创建组件实例前被调用,可以用来初始化组件的数据和方法。追踪响应式依赖可以通过新的reactive函数和ref函数来实现。这些新特性使得Vue 3更加灵活和高效,能够更好地满足开发者的需求。
1.生命周期和生命周期的四个阶段
生命周期(Life Cycle)在Vue.js中指的是组件从创建到销毁的过程,它包括了一系列的钩子函数,这些钩子函数会在特定的阶段被Vue自动调用。以下是Vue组件生命周期中的四个主要阶段及每个阶段的一个例子:
-
初始化/挂载阶段 (Initialization/Mounting)
beforeCreate
:在这个阶段,数据观测和事件配置都还未生效,此时组件的选项对象还没有完全初始化。beforeCreate() { console.log('组件实例正在创建中...'); }
created
:在此时,Vue实例已经完成所有数据绑定、属性注入等操作,但DOM尚未渲染。created() { console.log('组件实例已创建'); // 可以在这里进行API请求或其他初始化逻辑 }
beforeMount
:在这一步,模板编译完成,即将挂载至DOM节点前。beforeMount() { console.log('模板编译已完成,即将挂载到DOM'); }
mounted
:组件被成功挂载到DOM上后执行此钩子。mounted() { console.log('组件已被挂载到DOM上'); // 在这里可以访问到DOM元素并进行操作 }
-
更新阶段 (Updating)
beforeUpdate
:当组件数据发生改变,触发重新渲染之前执行。beforeUpdate() { console.log('组件数据即将更新,DOM未刷新'); }
updated
:组件完成数据更新,新的虚拟DOM树与旧的DOM树对比差异,并将实际变化的部分应用到真实的DOM中后执行。updated() { console.log('组件数据已更新,DOM已刷新'); // 此处可执行依赖于新DOM状态的操作 }
-
卸载阶段 (Unmounting)
beforeDestroy
:在组件销毁之前,用于清理资源或执行一些清理工作。beforeDestroy() { console.log('组件即将被销毁,清理定时器或取消订阅等'); // 这里可以清除任何定时器或者解绑监听器 }
destroyed
:组件已经被销毁,所有的数据绑定、指令、事件监听器都被解绑,子组件也都被销毁。destroyed() { console.log('组件已被销毁'); // 通常不会在这里做任何操作,因为组件已脱离了Vue管理 }
通过这些生命周期钩子,开发者能够精确地控制组件在不同阶段的行为和交互。
2.生命周期两个例子-初始化渲染和获取焦点
初始化渲染阶段:
<div id="app">
<input ref="myInput" v-model="message" @focus="onFocus">
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello, Vue!'
},
beforeCreate() {
console.log('beforeCreate: 组件实例正在创建,但数据和事件尚未绑定');
},
created() {
console.log('created: 组件实例已经创建完成,数据已绑定但DOM未挂载');
},
beforeMount() {
console.log('beforeMount: 模板编译已完成,即将开始挂载到DOM中');
},
mounted() {
console.log('mounted: 组件已经被挂载到DOM上,可以操作DOM');
// 如果需要在组件挂载后立即获取焦点
this.$refs.myInput.focus();
}
});
</script>
在这个例子中,我们展示了Vue生命周期中的几个关键钩子函数用于初始化渲染阶段:
beforeCreate
:当实例被创建时调用,此时数据观测、属性方法等还不可用。created
:实例已经创建完成,所有数据属性已存在,但DOM还未生成。beforeMount
:模板编译完成,即将开始挂载到真实的DOM节点上。mounted
:组件及其子组件均已完成挂载,并且DOM元素也已完全更新。在此处,我们使用了ref
来引用一个输入框元素,并在其挂载后通过this.$refs.myInput.focus()
使其获得焦点。
获取焦点阶段(用户交互):
methods: {
onFocus() {
console.log('onFocus: 输入框获取焦点');
// 在这里可以执行一些与焦点相关的逻辑,如记录时间点、验证输入等
}
}
当用户点击或通过其他方式使输入框获取焦点时,触发@focus
事件处理器onFocus
方法,该方法将在实际应用中处理与焦点相关的业务逻辑。
3.记账清单-渲染&添加&删除
假设我们正在构建一个简单的“小黑记账清单”应用,我们可以使用JavaScript(这里以React为例)来实现数据的渲染、添加和删除操作。以下是一个简化的例子:
import React, { useState } from 'react';
const initialItems = [
{ id: 1, description: '午餐', amount: 25 },
];
function BlackAccountBook() {
const [items, setItems] = useState(initialItems);
// 添加新记录的方法
const addItem = (description, amount) => {
const newItem = { id: Date.now(), description, amount };
setItems([...items, newItem]);
};
// 删除记录的方法
const removeItem = (itemId) => {
const updatedItems = items.filter(item => item.id !== itemId);
setItems(updatedItems);
};
return (
<div>
<h1>小黑记账清单</h1>
<ul>
{items.map(item => (
<li key={item.id}>
{item.description} - {item.amount}元
<button onClick={() => removeItem(item.id)}>删除</button>
</li>
))}
</ul>
<form onSubmit={(e) => {
e.preventDefault();
const desc = e.target.description.value;
const amt = parseFloat(e.target.amount.value);
if (desc && !isNaN(amt)) {
addItem(desc, amt);
e.target.reset();
}
}}>
<input type="text" name="description" placeholder="记账描述" />
<input type="number" name="amount" placeholder="金额" />
<button type="submit">添加</button>
</form>
</div>
);
}
export default BlackAccountBook;
在这个例子中:
- 我们首先定义了一个状态变量
items
用于存储记账清单的数据,并通过useState
钩子初始化。 addItem
函数负责接收新的记账条目信息,并将其合并到现有的items列表中。removeItem
函数根据传入的ID从items列表中移除对应的记账条目。- 渲染部分,我们遍历
items
数组并为每个条目生成一个列表项(<li>
),每个条目旁边都有一个删除按钮,点击时调用removeItem
方法。 - 在页面底部有一个表单,用户可以填写记账描述和金额,提交表单时会触发
onSubmit
事件处理器,将新记录添加到清单中,同时清空表单内容。
这个组件展示了如何在实际应用中进行数据的渲染、添加与删除操作。
4.记账清单-饼图渲染
假设小黑记账清单应用需要展示一个饼图,用于可视化不同类别的消费比例。我们可以使用react-chartjs-2
库配合Chart.js
来实现这个功能。以下是一个如何渲染饼图的例子:
import React from 'react';
import { Pie } from 'react-chartjs-2';
// 假设我们已经对记账数据进行了分类统计,并得到如下格式的数据:
const spendingCategories = [
{ label: '餐饮', value: 35 },
{ label: '交通', value: 15 },
{ label: '购物', value: 25 },
{ label: '娱乐', value: 20 },
];
// 将分类数据转换为Chart.js所需的配置格式
const data = {
labels: spendingCategories.map(item => item.label),
datasets: [{
data: spendingCategories.map(item => item.value),
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0'], // 颜色自定义
}],
};
function BlackAccountBookPieChart() {
return (
<div>
<h2>消费类别分布</h2>
<Pie data={data} options={{
maintainAspectRatio: false,
responsive: true,
legend: {
position: 'bottom',
},
}} />
</div>
);
}
export default BlackAccountBookPieChart;
在这个例子中:
- 我们首先根据记账清单中的类别数据生成了
data
对象,这是Chart.js Pie图所需的输入数据格式。 - 然后在
BlackAccountBookPieChart
组件中使用<Pie>
组件来渲染饼图,并将上述的data
对象作为其属性值。 - 同时设置了图表的一些基本选项,如保持纵横比、响应式布局以及图例的位置。
要使这个示例运行,你需要确保已经安装并导入了react-chartjs-2
和chart.js
库。实际项目中,你可能还需要从全局状态或通过props传递分类统计数据到该组件。
5.工程化开发和脚手架
工程化开发和脚手架在现代前端开发中扮演着至关重要的角色,它们简化了项目的初始化、配置管理和构建流程。以Vue.js为例,Vue CLI(Vue命令行工具)是一个广泛使用的脚手架,用于快速搭建Vue项目结构并提供了一套完整的工程化解决方案。
下面是一个使用Vue CLI创建和开发项目的简单步骤:
-
安装Vue CLI:
首先确保你已经全局安装了Vue CLI:npm install -g @vue/cli
-
创建新项目:
使用Vue CLI创建一个新的Vue应用:vue create my-project
这将引导你通过一系列交互式选项来选择预设或自定义项目配置,包括Babel、TypeScript支持、CSS处理器、路由管理器(Vue Router)、状态管理器(Vuex)等。
-
项目结构生成:
完成配置后,Vue CLI会自动创建一个包含标准工程化结构的项目目录,如:my-project/ ├── node_modules/ ├── public/ └── index.html └── favicon.ico ├── src/ ├── assets/ ├── components/ ├── App.vue ├── main.js ├── router/ └── index.js └── store/ (如果选择了Vuex) └── index.js ├── .gitignore ├── package.json ├── babel.config.js ├── README.md └── ...
-
编码与开发:
在src
目录下编写组件,并在main.js
中注册这些组件。利用热重载功能,在开发模式下修改代码时自动刷新浏览器内容。 -
编译与构建:
Vue CLI集成了Webpack,提供了开箱即用的编译和构建脚本。运行以下命令启动开发服务器:cd my-project npm run serve
或者进行生产环境构建:
npm run build
构建过程会完成代码压缩、资源优化、静态文件复制等一系列任务,并将结果输出到一个适合部署的目录中。
通过这种方式,Vue CLI作为工程化开发的脚手架,极大地提高了开发效率,统一了项目结构,确保了最佳实践的应用,同时也简化了不同环境下的构建流程。
6.项目目录介绍和运行流程
项目目录介绍通常是指软件开发中项目的文件结构和每个目录、文件的用途说明。不同的开发框架或平台有不同的标准项目结构,下面以几个常见的项目类型为例来介绍:
Vue.js 项目目录简介与运行流程
Vue CLI 创建的项目目录结构:
my-vue-project/
├── node_modules/ # npm 包依赖存放位置
├── public/
│ ├── favicon.ico # 网站图标
│ └── index.html # 应用入口HTML文件,通常会被Webpack处理并注入生成的JS/CSS资源
├── src/
│ ├── assets/ # 静态资源目录,如图片、字体等
│ ├── components/ # Vue 组件目录
│ │ ├── App.vue # 根组件
│ │ └── ...
│ ├── main.js # 入口JS文件,用于初始化Vue应用并挂载到index.html指定DOM元素上
│ ├── router/ # 路由配置目录(如果使用了Vue Router)
│ │ └── index.js
│ ├── store/ # Vuex状态管理器目录(如果使用了Vuex)
│ │ └── index.js
│ └── views/ # 页面级别的Vue组件
│ └── ...
├── .babelrc # Babel编译器配置文件
├── .gitignore # Git忽略文件列表
├── package.json # npm包元信息及脚本配置
├── README.md # 项目文档
└── vue.config.js # Vue CLI的项目级配置文件
运行流程:
- 在命令行下进入项目根目录。
- 安装npm依赖:
npm install
或yarn install
。- 运行开发服务器:
npm run serve
。- Webpack会监听源代码变化,并自动重新编译构建。
- 浏览器打开
http://localhost:8080/
(默认端口),可以看到应用程序在浏览器中运行。- 修改
src
下的任何文件,系统将自动热更新。
7.组件化开发和根组件
在组件化开发中,一个应用或页面通常被划分为多个可复用的、独立的功能模块,这些模块就是所谓的“组件”。每个组件都有自己的视图结构(HTML模板)、样式(CSS)和行为逻辑(JavaScript)。Vue.js框架是一个非常适合组件化开发的前端框架。
根组件示例:
在Vue应用中,App.vue
通常是整个应用程序的根组件。它的内容可能如下:
<!-- App.vue -->
<template>
<div id="app">
<!-- 这里可以引用子组件 -->
<HeaderComponent />
<MainContent />
<FooterComponent />
</div>
</template>
<script>
import HeaderComponent from './components/HeaderComponent.vue';
import MainContent from './components/MainContent.vue';
import FooterComponent from './components/FooterComponent.vue';
export default {
name: 'App',
components: {
HeaderComponent,
MainContent,
FooterComponent
},
// ... 其他脚本逻辑
};
</script>
<style scoped>
/* 根组件的局部样式 */
</style>
在这个例子中,《App.vue》是根组件,它包含了三个子组件:HeaderComponent
、MainContent
和 FooterComponent
。每个子组件分别负责页面头部、主要内容区域以及页脚部分的渲染和交互逻辑。
子组件(例如 HeaderComponent)示例:
<!-- HeaderComponent.vue -->
<template>
<header class="site-header">
<h1>我的网站标题</h1>
<nav>
<ul>
<li><router-link to="/">首页</router-link></li>
<li><router-link to="/about">关于我们</router-link></li>
</ul>
</nav>
</header>
</template>
<script>
export default {
name: 'HeaderComponent',
// ... 可能包含的其他逻辑如生命周期钩子、计算属性等
};
</script>
<style scoped>
.site-header {
/* 头部组件的样式 */
}
</style>
通过这样的组织方式,各个组件各自负责一部分UI和功能,并且可以单独测试和维护,提高了代码的复用性和项目的整体可维护性。
8.普通组件的注册-局部注册
在Vue.js中,普通组件的局部注册意味着一个组件只在其定义或引入的父组件作用域内可用。以下是一个Vue 2.x版本的局部注册组件的例子:
假设我们有一个名为MyButton
的普通组件,它位于components/MyButton.vue
文件中。
MyButton.vue (子组件)
<template>
<button @click="handleClick">{{ label }}</button>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '点击我'
}
},
methods: {
handleClick() {
alert('按钮被点击了!');
}
}
};
</script>
<style scoped>
button {
background-color: #4CAF50;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
}
</style>
然后,在使用该组件的父组件(例如 App.vue
)中,我们可以局部注册并使用 MyButton
组件:
App.vue (父组件)
<template>
<div id="app">
<!-- 使用局部注册的 MyButton 组件 -->
<my-button label="登录"></my-button>
</div>
</template>
<script>
import MyButton from './components/MyButton.vue'; // 引入自定义组件
export default {
components: {
// 局部注册 MyButton 组件
MyButton
}
};
</script>
<style>
/* 父组件样式 */
</style>
在这个例子中,MyButton
组件只在 App.vue
组件内部是可识别和使用的。如果其他组件需要使用 MyButton
组件,它们必须各自导入并局部注册这个组件。
9.普通组件的注册-全局注册
在Vue.js中,全局注册组件意味着该组件在整个应用的任何地方都可以被引用和使用。以下是一个Vue 2.x版本全局注册组件的例子:
假设我们有一个名为MyButton
的普通组件,它位于components/MyButton.vue
文件中。
MyButton.vue (子组件)
<template>
<button @click="handleClick">{{ label }}</button>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '点击我'
}
},
methods: {
handleClick() {
alert('按钮被点击了!');
}
}
};
</script>
<style scoped>
button {
background-color: #4CAF50;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
}
</style>
然后,在项目的入口文件(如 main.js
)中全局注册这个组件:
main.js
import Vue from 'vue';
import MyButton from './components/MyButton.vue'; // 引入自定义组件
// 全局注册 MyButton 组件
Vue.component('my-button', MyButton);
new Vue({
render: h => h(App)
}).$mount('#app');
现在,在整个应用程序中的任意一个Vue组件内,你都可以直接使用 <my-button>
标签来插入这个全局注册的组件,无需在每个组件内部单独导入和声明。
例如,在另一个名为 Home.vue
的组件中使用:
Home.vue
<template>
<div class="home">
<!-- 直接使用全局注册的 MyButton 组件 -->
<my-button label="登录"></my-button>
</div>
</template>
<script>
export default {
// 这里无需再引入或注册 MyButton 组件
};
</script>
<style scoped>
/* Home组件样式 */
</style>
最后求点赞,求分享,求抱抱…