一、vue生命周期
-
beforeCreate:
- 调用时机:在实例初始化之后,数据观测 (data observer) 和事件配置 (event/watcher setups) 之前调用。
- 说明:在这个阶段,实例已经初始化,但是尚未完成数据的观测和事件的初始化。
-
created:
- 调用时机:在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调等。
- 说明:在
created
钩子被调用时,Vue 实例已经完成了数据观测,但尚未开始 DOM 的挂载和渲染。
-
beforeMount:
- 调用时机:在挂载开始之前被调用,即
el
被新创建的vm.$el
替换,并挂载到实例上去之前调用该钩子函数。 - 说明:这个阶段发生在模板编译成虚拟 DOM 并在将其渲染到页面之前。
- 调用时机:在挂载开始之前被调用,即
-
mounted:
- 调用时机:在实例挂载到 DOM 后被调用。
- 说明:
mounted
钩子被调用时,Vue 实例已经完成了挂载,vm.$el
已经挂载到实际的 DOM 元素上,可以进行 DOM 操作。
-
beforeUpdate:
- 调用时机:在数据更新之前调用,发生在虚拟 DOM 重新渲染和打补丁之前。
- 说明:在这个阶段,可以在更新之前访问现有的 DOM。
-
updated:
- 调用时机:在数据更新之后调用,发生在虚拟 DOM 重新渲染和打补丁之后。
- 说明:
updated
钩子被调用时,DOM 已经重新渲染,可以执行依赖于 DOM 的操作。
-
beforeDestroy:
- 调用时机:在实例销毁之前调用。在这一步,实例仍然完全可用。
- 说明:可以在这个阶段进行一些清理工作,如取消定时器、取消事件监听等。
-
destroyed:
- 调用时机:在实例销毁之后调用。该钩子被调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
- 说明:在这个阶段,Vue 实例已经被完全清理,不再可用。
图解
摘自vue的生命周期图解_vue生命周期图 橙子-CSDN博客
二、MVVM
MVVM 是一种软件架构模式,用于构建用户界面。它包含三个核心部分:Model、View 和 ViewModel。
-
Model:
- 定义:Model 代表应用程序中用于处理数据逻辑的部分。它负责管理应用程序的数据和业务逻辑。
- 作用:Model 主要关注数据的存储、获取、操作以及与服务器的交互,通常包括数据的验证和处理逻辑。
-
View:
- 定义:View 是用户直接与之交互的界面部分。它可以是一个页面、一个按钮、一个表单等用户可以看到和操作的界面元素。
- 作用:View 负责展示数据给用户,并接收用户的输入操作。
-
ViewModel:
- 定义:ViewModel 是连接 View 和 Model 的中间件或者抽象层。它负责在 View 和 Model 之间进行数据传输和交互。
- 作用:ViewModel 将 Model 中的数据转换为 View 可以直接使用的格式,并且响应 View 的用户操作,更新 Model 的数据。它通常包含了业务逻辑和数据展示逻辑,负责将数据绑定到 View 上。
数据同步
在 MVVM 架构中,数据同步指的是 ViewModel 和 View 之间的双向数据绑定,以及 ViewModel 和 Model 之间的数据交互:
-
ViewModel 和 View 的数据同步:
- ViewModel 将 Model 的数据通过数据绑定技术(如 Vue.js 的指令或者 Angular 的双向数据绑定)绑定到 View 上,从而实现数据的展示。
- 当用户在 View 中输入数据或者操作界面元素时,ViewModel 接收到用户的操作,更新数据到 Model 中,确保数据的一致性和同步更新。
-
ViewModel 和 Model 的数据同步:
- ViewModel 负责将 Model 中的数据映射到 View 上,并且响应 View 中用户的操作。
- 如果用户在 View 中进行了修改,ViewModel 负责将修改的数据同步到 Model 中,保持数据的更新和一致性。
具体实现
v-model
是 Vue.js 框架中用于实现双向数据绑定的指令。它充分体现了 MVVM(Model-View-ViewModel)模式中的双向数据绑定特性。下面我们将详细解释 v-model
如何体现 MVVM 和双向绑定:
1.MVVM 模式
MVVM 模式是一种软件架构设计模式,它将应用程序分为三个部分:
- Model(模型):代表应用程序的数据和业务逻辑。
- View(视图):用户界面,负责数据的展示。
- ViewModel(视图模型):连接 Model 和 View 的桥梁,它负责将 Model 的数据转换为 View 可以展示的格式,并处理 View 的事件,更新 Model。
2.双向数据绑定
双向数据绑定意味着 Model 的变化会自动更新 View,同时 View 的变化也会自动更新 Model。这样,开发者无需手动编写代码来同步数据。
3.v-model
如何体现 MVVM 和双向绑定
在 Vue.js 中,v-model
指令用于在 input、textarea 或 select 等表单元素上创建双向数据绑定。它简化了 Model 和 View 之间的数据同步。
示例:
假设我们有一个简单的 Vue 应用,其中有一个输入框和一个显示文本的区域。
<div id="app">
<input v-model="message" placeholder="编辑我...">
<p>消息内容是:{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: ''
}
})
</script>
在这个例子中:
- Model:是 Vue 实例中的
data
对象,这里包含了message
属性。 - View:是 HTML 模板部分,包括输入框和显示文本的区域。
- ViewModel:是 Vue 实例本身,它连接了 Model 和 View。
当用户在输入框中输入文字时:
-
View 到 Model:输入框的值变化会触发
input
事件,v-model
会捕获这个事件,并更新 Vue 实例中message
的值。这是从 View 到 Model 的更新。 -
Model 到 View:当你通过JavaScript修改
message
属性的值时,由于v-model
的双向绑定特性,输入框的显示内容也会随之改变,以及使用插值表达式{{ message }}
的文本区域。这是从 Model 到 View 的更新。
因此,v-model
通过监听 DOM 事件和更新数据属性,在 View 和 Model 之间建立了双向数据绑定,从而简化了 MVVM 模式中的数据同步过程。开发者无需手动编写代码来处理数据的同步,提高了开发效率和代码的可维护性。
动态布局
动态布局(Dynamic Layout)通常指的是根据不同的条件或者数据动态地调整页面的布局结构或样式,以适应不同的设备、用户需求或应用状态。在前端开发中,实现动态布局可以通过以下几种方式:
-
响应式设计(Responsive Design):
- 使用 CSS 媒体查询和弹性网格布局(如Flexbox或Grid),使网页能够根据用户设备的屏幕尺寸自动调整布局和样式。这种方式可以确保在不同设备上(如桌面、平板、手机)都能有良好的显示效果。
-
条件渲染(Conditional Rendering):
- 根据应用状态或用户权限等条件,动态地显示或隐藏特定的组件、部件或页面区域。Vue.js 和 React 等前端框架提供了条件渲染的支持,可以根据数据状态来动态地改变视图的呈现方式。
-
动态样式绑定(Dynamic Styling):
- 根据组件的状态或数据,动态地绑定样式属性。可以通过绑定
class
或者style
对象来实现。这使得页面的样式可以随着用户的操作或者数据的变化而动态更新,提升用户体验和交互性。
- 根据组件的状态或数据,动态地绑定样式属性。可以通过绑定
-
组件化开发(Component-Based Development):
- 将页面划分为独立的组件,每个组件负责特定的功能或视图。通过组合不同的组件,可以灵活地构建出多样化的页面布局和功能组合,便于管理和维护。
-
动态路由(Dynamic Routing):
- 根据用户的操作或者权限,动态地加载不同的路由页面或视图。这种方式通常用于构建单页应用(SPA),使得用户在应用内部导航时可以有流畅的体验。
-
数据驱动视图(Data-Driven Views):
- 根据后端返回的数据动态地生成页面结构或内容。通过数据绑定和模板渲染,可以使页面内容具备高度的灵活性和可定制性,适应不同的数据输入和条件。
在 Vue.js 中,v-if
和 v-show
都是用于控制元素显示与隐藏的指令,但它们之间有一些重要的区别:
v-if
-
使用场景:
v-if
是条件渲染指令,它根据表达式的真假来有条件地渲染元素。当表达式为真时,元素被渲染;为假时,元素从 DOM 中移除。
-
DOM 操作:
- 当条件为假时,Vue.js 会从 DOM 中移除该元素及其所有子组件,不会渲染它们。这样做的好处是可以减少不必要的 DOM 操作,节省性能。
-
初始渲染消耗:
- 如果初始条件为假,元素将不会被渲染到页面上。只有当条件变为真时,元素才会被动态添加到页面中。
-
适用性:
- 适用于需要在运行时频繁切换条件以显示不同内容的场景,因为它能够彻底从 DOM 中移除元素。
v-show
-
使用场景:
v-show
也是用于控制元素的显示与隐藏,但是它始终将元素保留在 DOM 中,并通过 CSS 样式控制其显示与隐藏。当表达式为真时,元素显示(即display: none
变为display: block
或display: inline
,具体取决于元素本身的默认样式);为假时,元素隐藏(即display: block
或display: inline
变为display: none
)。
-
DOM 操作:
- 不管条件是真还是假,元素始终存在于 DOM 中,只是通过 CSS 的
display
属性来控制其显示状态。
- 不管条件是真还是假,元素始终存在于 DOM 中,只是通过 CSS 的
-
初始渲染消耗:
- 如果初始条件为假,元素会被渲染到页面上,但是会被设置为
display: none
,因此在初始加载时有一定的性能消耗。
- 如果初始条件为假,元素会被渲染到页面上,但是会被设置为
-
适用性:
- 适用于需要频繁切换元素显示状态但不希望每次切换时重新渲染 DOM 的场景,比如需要快速切换展示一个元素。
三、Axious异步请求
当使用 Axios 在 Vue.js 中进行异步请求时,可以使用 axios.get
和 axios.post
方法来发送 GET 和 POST 请求。
axios.request(config)
axios.get(url[, config]) // 只支持 params 传参--用于获取数据。
axios.delete(url[, config]) // 只支持 params传参 --用于删除数据。
axios.head(url[, config]) // 只支持 params传参
axios.post(url[, data[, config]]) // 同时支持 data 和 params --用于提交数据(新建)、包括表单提交及文件上传。
axios.put(url[, data[, config]]) // 同时支持 data 和 params --用于更新数据(修改),将所有数据都推送到后端。
axios.patch(url[, data[, config]]) // 同时支持 data 和 params --用于更新数据(修改),只将修改的数据推送到后端。
以下是简单的示例代码:
GET 请求示例:
假设我们要从服务器获取用户列表:
// 导入 Axios import axios from 'axios'; // 在 Vue 组件中使用 Axios 发送 GET 请求 axios.get('https://jsonplaceholder.typicode.com/users') .then(response => { // 请求成功时的处理 console.log('获取用户列表成功:', response.data); // 在 Vue 组件中可以将数据保存到 data 中,供模板渲染使用 this.users = response.data; }) .catch(error => { // 请求失败时的处理 console.error('获取用户列表失败:', error); });
在这个示例中:
axios.get
方法发送了一个 GET 请求到指定的 URL (https://jsonplaceholder.typicode.com/users
)。then
方法用于处理请求成功时的逻辑,获取到的响应数据位于response.data
中。catch
方法用于处理请求失败时的逻辑,并打印出错误信息。
POST 请求示例:
假设我们要向服务器提交用户的表单数据:
// 导入 Axios import axios from 'axios'; // 数据准备,假设这是用户提交的表单数据 const formData = { name: 'John Doe', email: 'john.doe@example.com', message: 'Hello from Axios POST request!' }; // 在 Vue 组件中使用 Axios 发送 POST 请求 axios.post('https://jsonplaceholder.typicode.com/posts', formData) .then(response => { // 请求成功时的处理 console.log('提交表单成功:', response.data); // 可以根据需要处理服务器返回的数据 }) .catch(error => { // 请求失败时的处理 console.error('提交表单失败:', error); });
在这个示例中:
axios.post
方法发送了一个 POST 请求到指定的 URL (https://jsonplaceholder.typicode.com/posts
),同时将formData
对象作为请求体发送给服务器。then
方法用于处理请求成功时的逻辑。catch
方法用于处理请求失败时的逻辑,并打印出错误信息。
这些示例展示了如何在 Vue.js 中使用 Axios 发送 GET 和 POST 请求,并处理返回的数据或错误。记得在实际项目中,替换示例中的 URL 和数据为你的实际接口地址和需要发送的数据。
PUT 请求示例:
<script>
import axios from 'axios'
export default {
name: 'get请求',
components: {},
created() {
//写法一
let data = {
id:12
}
axios.put('接口地址', data}).then(
(res) => {
//执行成功后代码处理
}
)
//写法二
axios({
method: 'put',//请求方法
data: data,
url: '后台接口地址',
}).then(res => {
//执行成功后代码处理
})
}
}
</script>
PATCH 请求示例:
<script>
import axios from 'axios'
export default {
name: 'get请求',
components: {},
created() {
//写法一
let data = {
id:12
}
axios.patch('接口地址', data}).then(
(res) => {
//执行成功后代码处理
}
)
//写法二
axios({
method: 'patch',//请求方法
data: data,
url: '后台接口地址',
}).then(res => {
//执行成功后代码处理
})
}
}
</script>
DELETE 请求示例:
<script>
import axios from 'axios'
export default {
name: 'get请求',
components: {},
created() {
//写法一
let data = {
id:12
}
//url传递参数
axios.delete('接口地址', {
parmas:{
id:12
}
}).then(
(res) => {
//执行成功后代码处理
}
)
//post方式传递参数
axios.delete('接口地址', {
data:{
id:12
}
}).then(
(res) => {
//执行成功后代码处理
}
)
//写法二
axios({
method: 'patch',//请求方法
parmas:{
id:12
},
url: '后台接口地址',
}).then(res => {
//执行成功后代码处理
})
}
}
</script>
在 Vue.js 中路由的带参传递:
在前端框架中,如Vue.js或React等,通常使用路由(Router)来管理不同页面之间的导航和状态传递。路由的带参传递指的是在切换路由时,通过URL参数或路由参数传递数据,以便目标页面可以根据这些参数进行显示或处理。
1. 通过路由参数传递:
- 在定义路由时,可以使用动态路由参数来传递数据。例如,在路由配置中定义动态参数:
const routes = [
{ path: '/user/:userId', component: UserPage }
];
在这里,:userId
就是一个动态的路由参数。
- 在组件内部可以通过
$route.params
来访问路由参数:
<template>
<div>
<p>User ID: {{ $route.params.userId }}</p>
</div>
</template>
- 导航时传递参数:
2. 通过查询参数传递:
-
查询参数是在URL中以
?key=value
的形式传递的参数,例如/user?userId=123
。 -
在组件内部可以通过
$route.query
访问查询参数:
<template>
<div>
<p>User ID: {{ $route.query.userId }}</p>
</div>
</template>
- 导航时传递查询参数:
// 通过 router-link 导航
<router-link :to="{ path: '/user', query: { userId: 123 } }">User</router-link>
// 或者通过编程式导航
this.$router.push({ path: '/user', query: { userId: 123 } });
注意事项:
- 使用路由参数适合传递较为固定且不频繁变动的数据,如用户ID等。
- 使用查询参数适合传递较为灵活和频繁变动的数据,如搜索关键词等。
- 在路由参数传递时,需要在路由配置中声明动态参数,并在组件内部通过
$route.params
访问。 - 在查询参数传递时,直接在导航链接或编程式导航时指定
query
对象即可。
懒加载
懒加载(Lazy Loading)是一种优化技术,用于延迟加载应用程序中的资源(如图片、JavaScript、CSS等),直到这些资源确实需要使用时才加载。这种技术可以帮助减少初始加载时的资源请求和加载时间,提升页面的加载速度和用户体验。
在前端开发中,懒加载通常用于以下几个方面:
-
图片懒加载:
- 当页面中有很多图片时,不必一开始就加载所有图片,而是等到用户滚动到可见区域时再加载对应的图片。这可以通过监听滚动事件来实现,或者使用现成的库如
IntersectionObserver
来自动处理。
- 当页面中有很多图片时,不必一开始就加载所有图片,而是等到用户滚动到可见区域时再加载对应的图片。这可以通过监听滚动事件来实现,或者使用现成的库如
-
组件懒加载:
- 对于大型的单页应用(SPA),为了减少初始加载时间,可以将某些组件延迟加载,直到用户访问相关路由时才进行加载。这种技术称为路由懒加载(Route-based Lazy Loading)。
路由懒加载是指将应用的不同路由对应的组件分割成独立的代码块,然后当路由被访问时再加载对应的组件代码。这种做法可以显著减少初始加载时的 JavaScript 文件大小,加快应用的初始加载速度。
在 Vue.js 中实现路由懒加载可以通过以下步骤:
-
使用
import()
函数动态导入组件,返回一个 Promise 对象。这个函数可以在 webpack 等现代构建工具中自动转换为代码分割(code splitting)的实现。 -
在路由配置中使用
import()
函数来指定组件的加载方式,例如:
const Foo = () => import('./Foo.vue');
- 在路由配置中,将懒加载的组件与对应的路由路径关联起来:
const routes = [
{ path: '/foo', component: () => import('./Foo.vue') }
];
四、组件通信
在 Vue.js 中,父组件可以通过以下几种方式监听子组件触发的事件:
-
使用
v-on
或@
语法:
在父组件的模板中,可以使用 v-on
或 @
(语法糖)来监听子组件触发的自定义事件。
<!-- 子组件 MyButton.vue -->
<template>
<button @click="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
this.$emit('button-clicked', 'some data');
}
}
}
</script>
<!-- 父组件 ParentComponent.vue -->
<template>
<div>
<my-button @button-clicked="handleButtonClick"></my-button>
</div>
</template>
<script>
import MyButton from './MyButton.vue';
export default {
components: {
MyButton
},
methods: {
handleButtonClick(data) {
console.log('Button clicked in child component with data:', data);
}
}
}
</script>
在上述示例中,子组件 MyButton.vue
中通过 this.$emit('button-clicked', 'some data');
触发了一个名为 button-clicked
的自定义事件,并传递了一个数据 'some data'
。父组件 ParentComponent.vue
使用 v-on
或 @
语法监听了这个事件,并在 handleButtonClick
方法中处理事件触发。
2. 使用 .sync
修饰符:
- 如果需要在父组件中修改子组件的 prop,可以使用
.sync
修饰符来实现双向绑定,并监听子组件触发的更新事件。
示例:
<!-- 子组件 Counter.vue -->
<template>
<button @click="increment">Increment</button>
</template>
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
this.$emit('update:count', this.count); // 触发更新事件
}
}
}
</script>
<!-- 父组件 ParentComponent.vue -->
<template>
<div>
<p>Count: {{ totalCount }}</p>
<counter :count.sync="totalCount"></counter>
</div>
</template>
<script>
import Counter from './Counter.vue';
export default {
components: {
Counter
},
data() {
return {
totalCount: 0
};
}
}
</script>
在这个例子中,子组件 Counter.vue
中通过 this.$emit('update:count', this.count);
触发了一个名为 update:count
的更新事件,父组件 ParentComponent.vue
使用 .sync
修饰符监听了这个事件,并将 totalCount
的值同步更新为子组件中的 count
值。
3. 通过 $refs
访问子组件的方法或属性:
- 如果子组件并不是通过事件触发交互,而是需要直接调用子组件的方法或访问其属性,可以使用
$refs
来访问子组件的实例。
示例:
<!-- 子组件 ChildComponent.vue -->
<template>
<button @click="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
console.log('Button clicked in child component');
}
}
}
</script>
<!-- 父组件 ParentComponent.vue -->
<template>
<div>
<button @click="callChildMethod">Call Child Method</button>
<child-component ref="childRef"></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
callChildMethod() {
this.$refs.childRef.handleClick();
}
}
}
</script>