文本插值
{{ }} 即双大括号。
<template>
<h3>模板语法</h3>
<p>{{ msg }}</p>
</template>
<script>
export default {
data(){
return{
msg: "神奇的语法"
}
}
}
</script>
<style>
</style>
原始html
输出原始html,需要使用v-html语法。
<template>
<p>纯文本:{{ rawHtml }}</p>
<p>属性:<span v-html="rawHtml"></span></p>
</template>
<script>
export default {
data() {
return {
rawHtml: "<a href='https://itbaizhan.com'>百战程序员</a>"
}
}
}
</script>
属性绑定
class、style等属性值的绑定使用v-bing:或:。
也就是与script中的data中的变量的绑定。
<template>
<div v-bind:id="dynamicId" v-bind:class="dynamicClass">测试</div>
</template>
<script>
export default {
data() {
return {
dynamicClass: "appclass",
dynamicId: "appid"
}
}
}
</script>
条件渲染
v-if v-else v-else-if v-show 表达式返回true值时渲染,否则不渲染。
<template>
<h3>条件渲染</h3>
<div v-if="flag">你能看见我么</div>
<div v-else>那你还是看看我吧</div>
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>Not A/B/C</div>
<div v-show="flag">你能看见我么</div>
</template>
<script>
export default {
data() {
return {
flag: true,
type: "B"
}
}
}
</script>
列表渲染
使用v-for指令。
我们可以用v-for指令基于一个数组来渲染一个列表。 v-for 指令需要使用item in items形式的特殊语法,其中items是源数据数组,而item则是被迭代的数组元素的别名。
代码中的index可以理解为数组的下标。
为什么要加key属性(不加key的情况下,列表元素变动顺序时,会进行重新渲染每一个元素,而不是只进行排序操作。):
当 Vue 正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的keyattribute。
<template>
<div class="hello">
<h3>列表渲染</h3>
<ul>
<li v-for="(item,index) in newsList" :key="item.id">
{{ item.title }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
newsList:[
{
id:1001,
title:"今日新闻1"
},
{
id:1002,
title:"今日新闻2"
},
{
id:1003,
title:"今日新闻3"
},
{
id:1004,
title:"今日新闻4"
}
]
}
}
}
</script>
事件处理
使用v-on或简写@指令。
下面代码点击后触发addCount()方法。
<template>
<h3>内联事件处理器</h3>
<button @click="addCount">Add</button>
<p>{{ count }}</p>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
addCount() {
console.log("点击了");
}
}
}
</script>
获取event对象,就是JS的event对象:
<template>
<h3>内联事件处理器</h3>
<button @click="addCount">Add</button>
<p>{{ count }}</p>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
// event对象
addCount(e) {
// vue中的event对象,就是JS的event对象
console.log(e.target.innerHTML = "Add" + this.count);
this.count++;
}
}
}
</script>
传递参数:
传递参数过程中如果需要event对象,记得使用$event。
<template>
<h3>事件传参</h3>
<p @click="getNameHandler(item,$event)" v-for="(item, index) of names" :key="index">{{ item }}</p>
</template>
<script>
export default {
data() {
return {
names: ["iwen", "ime", "frank"]
}
},
methods: {
getNameHandler(name, e) {
console.log(name);
console.log(e);
}
}
}
</script>
事件修饰符
.stop.prevent.self.capture.once.passive
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
数组变化侦测
data中的数据为数组时,如果使用如下方法变更数组数据,会直接更新网页中显示内容。
使用下面这些方法会返回一个新的数组,而不会直接更新网页中的显示内容。
计算属性
模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。推荐使用计算属性来描述依赖响应式状态的复杂逻辑。
//模板语法难以维护
<template>
<h3>{{ itbaizhan.name }}</h3>
<p>{{ itbaizhan.content.length > 0 ? 'Yes' : 'No' }}</p>
</template>
<script>
export default {
data() {
return {
itbaizhan: {
name: "百战程序员",
content: ["前端", "Java", "python"]
}
}
}
}
</script>
//官方建议把复杂逻辑放入computed()处理。
<template>
<h3>{{ itbaizhan.name }}</h3>
<p>{{ itbaizhanContent }}</p>
</template>
<script>
export default {
data() {
return {
itbaizhan: {
name: "百战程序员",
content: ["前端", "Java", "python"]
}
}
},
// 计算属性
computed: {
itbaizhanContent() {
return this.itbaizhan.content.length > 0 ? 'Yes' : 'No';
}
}
}
</script>
class绑定
class绑定不只可以使用字符串,还可以使用组或对象。
//绑定对象和数组
<template>
<p :class="{ 'active': isActive, 'text-danger': hasError }">Class样式绑定1</p> //对象
<p :class="classObject">Class样式绑定2</p> //对象
<p :class="[arrActive, arrHasError]">Class样式绑定3</p> //数组
</template>
<script>
export default {
data() {
return {
isActive: true,
hasError: true
classObject: {
'active': true,
'text-danger': true
}
arrActive: "active",
arrHasError: "text-danger"
}
}
</script>
<style>
.active {
font-size: 30px;
}
.text-danger {
color: red;
}
</style>
//数组嵌套对象。数组和对象嵌套过程中,只能是数组嵌套对象,不能对象嵌套数组。
<template>
<div :class="[{ 'active': isActive }, errorClass]"></div> //数组嵌套对象
</template>
<script>
export default {
data() {
return {
isActive: true,
errorClass: "text-danger"
}
}
}
</script>
sytle绑定
sytle绑定不只可以使用字符串,还可以使用组或对象。同class绑定。
侦听器
语法watch,作用是监听页面的数据变化,只针对响应式的数据,也就是在data中所声明的,通过{{ }}模板语法绑定的数据。
<template>
<h3>侦听器</h3>
<p>{{ message }}</p>
<button @click="updateHandle">修改数据</button>
</template>
<script>
export default {
data() {
return {
message: "Hello"
}
},
methods: {
updateHandle() {
this.message = "World"
}
},
watch: {
// newValue: 改变之后的数据
// oldValue: 改变之前的数据
// 函数名必须与侦听的数据对象保持一致
message(newValue, oldValue) {
// 数据发生变化,自动执行的函数
console.log(newValue, oldValue);
}
}
}
</script>
表单输入绑定
语法v-model。下面代码,将输入框的内容与message绑定。
<template>
<h3>表单输入绑定</h3>
<form>
<input type="text" v-model="message">
<p>{{ message }}</p>
</form>
</template>
<script>
export default {
data() {
return {
message: ""
}
}
}
</script>
v-model修饰符
.lazy
默认情况下,v-model 会在每次 input 事件后更新数据 (IME 拼字阶段的状态例外)。你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据。
.number
如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入。
.trim
如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符。
模板引用(直接访问原始的DOM元素)
虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的refattribute。
挂载结束后引用都会被暴露在this.$refs之上。
<template>
<div ref="container" class="container">{{ content }}</div> //DOM元素div加ref属性
<button @click="getElementHandle">获取元素</button>
</template>
<script>
export default {
data() {
return {
content: "内容"
}
},
methods: {
getElementHandle() {
this.$refs.container.innerHTML = "哈哈哈"; //引用DOM元素div,使用原生js属性innerHTML操作。
}
}
}
</script>
没有特别的需要,尽量不要操作DOM。因为很麻烦。
组件组成
一个.vue文件,就是一个组件。包括:
<template>
包括html
</template>
<script>
包括逻辑,也就是js。
</script>
<style>
包括样式,也就是css。
</style>
在一个组件中引用另一个组件的步骤(三步走):
<template>
//第三步:显示组件
<MyComponent />
</template>
<script>
// 第一步:引入组件
import MyComponent from "./components/MyComponent.vue"
export default {
// 第二步:注入组件
components: {
MyComponent
}
}
</script>
<style>
</style>
样式增加scoped,会使样式只在当前组件中生效,否则会全局生效。
<style scoped>
</style>
组件全局注册
import { createApp } from 'vue'
import App from './App.vue'
import Header from "./pages/Header.vue"
const app = createApp(App)
// 在这中间写组件的注册
app.component("Header", Header)
app.mount('#app')
在最外层注册后,在所有组件中都可以直接引用Header.vue组件: <header />
全局注册虽然很方便,但有以下几个问题:
1.全局注册,但并没有被使用的组件无法在生产打包时被自动移除(也叫“tree-shaking”)。如果你全局注册了一个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。
2.全局注册在大型项目中使项目的依赖关系变得不那么明确。在父组件中使用子组件时,不太容易定位子组件的实现。和使用过多的全局变量一样,这可能会影响应用长期的可维护性。
组件数据传递(父传子)-props
props传递数据,只能父传子,不能子传父。
//父组件
<template>
<h3>Parent</h3>
<Child title="Parent数据1" demo = "Parent数据2" :demo2 = "message" /> //传给子组件
</template>
<script>
import Child from "./Child.vue"
export default {
data() {
return {
message = "Parent数据3"
}
},
components: {
Child
}
}
</script>
//子组件
<template>
<h3>Child</h3>
<p>{{ title }}</p> //使用
<p>{{ demo }}</p> //使用
<p>{{ demo1 }}</p> //使用
</template>
<script>
export default {
data() {
return {
}
},
props: ["title","demo","demo2"] //子组件接收
}
</script>
组件传递多种数据类型
通过 props 传递数据,不仅可以传递字符串类型的数据,还可以是其他类型,例如:数字、对象、数组等。但实际上任何类型的值都可以作为 props 的值被传递。
<template>
<h3>Parent</h3>
<Child :title="message" :age="age" :names="names" :userInfo="userInfo" />
</template>
<script>
import Child from "./Child.vue"
export default {
data() {
return {
message: "Parent数据!",
age: 20, //数字
names: ["iwen", "ime", "frank"], //数组
userInfo: { //对象
name: "iwen",
age: 20
}
}
},
components: {
Child
}
}
</script>
<template>
<h3>Child</h3>
<p>{{ title }}</p>
<p>{{ age }}</p> //数字
<ul>
<li v-for="(item, index) of names" :key="index">{{ item }}</li> //数组
</ul>
<p>{{ userInfo.name }}</p> //对象
<p>{{ userInfo.age }}</p>
</template>
<script>
export default {
data() {
return {
}
},
props: ["title", "age", "names", "userInfo"] //接收
}
</script>
组件传递props效验
<template>
<h3>ComponentA</h3>
<ComponentB :title="title" /> //传递过去
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data() {
return {
title: "标题", //这里必须是字符串
name:["lbsjs","wy","kaixin"] //数组
}
},
components: {
ComponentB
}
}
</script>
<template>
<h3>ComponentB</h3>
<p>{{ title }}</p>
<p>{{ age }}</p> //父组件没有传过来数据,会显示0,因为给出默认值。
<p v-for="(item, index) of names" :key="index">{{ item }}</p>
</template>
<script>
export default {
data() {
return {
}
},
props: {
title: {
type: String //指定传过来数据的类型
required:true //指定title为必填选项,如果父组件不传送数据过来,浏览器报警告。
}
age:{
type:Number
default:0 //可以指定默认值
}
//数字和字符串可以直接default给出默认值,但数组和对象,必须通过工厂函数返回默认值。
name:{
type:Array
default(){
return ["空"]
}
}
</script>
注意:props是只读的。
组件事件(自定义事件,子传父) -$emit
<template>
<h3>组件事件</h3>
<Child @someEvent="getHandle" />
</template>
<script>
import Child from "./Child.vue"
export default {
data() {
return {
message: ""
}
},
components: {
Child
},
methods: {
getHandle(data) {
console.log("触发了", data); //接收到子组件的数据。
}
}
}
</script>
<template>
<h3>Child</h3>
<button @click="clickEventHandle">传递数据</button> //点击按钮后,触发父组件的getHandle函数。
</template>
<script>
export default {
methods: {
clickEventHandle() {
// 自定义事件
this.$emit("someEvent","发给父元素") //getHandle函数会接收到第二个参数的数据。
}
}
}
</script>
组件事件 配合'v-model'使用
//SearchComponent.vue
<template>
搜索:<input type="text" v-model="search">
</template>
<script>
export default {
data() {
return {
search: ""
}
},
// 侦听器
watch: {
search(newValue, oldValue) {
this.$emit("searchEvent", newValue) //将newValue值传递给父组件
}
}
}
</script>
<template>
<h3>Main</h3>
<p>搜索内容为:{{ search }}</p>
<SearchComponent @searchEvent="getSearch"/>
</template>
<script>
import SearchComponent from "./SearchComponent.vue"
export default {
data() {
return {
search: ""
}
},
components: {
SearchComponent
},
methods: {
getSearch(data) {
this.search = data;
}
}
}
</script>
props实现子传父
//父组件
<template>
<h3>ComponentA</h3>
<ComponentB title="标题" :onEvent="dataFn" /> //将dataFn函数传给子组件
<p>{{ message }}</p> //显示子组件传来的数据
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data() {
return {
}
},
components: {
ComponentB,
message
},
methods: {
dataFn(data) {
console.log(data);
this.message = data
}
}
}
</script>
//子组件
<template>
<h3>ComponentB</h3>
<p>{{ title }}</p>
<p>{{ onEvent('传递数据') }}</p> //使用父组件函数,也就是把子组件数据传给父组件。
</template>
<script>
export default {
data() {
return {
}
},
props: {
title: String,
onEvent: Function
}
}
</script>
透传Attributes
本节日常使用较少,只进行了解。
当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上。
//父组件
<template>
<AttrComponents class="attr-container"/> //传给子组件attr-container属性传给子组件
</template>
<script>
import AttrComponents from "./components/AttrComponents.vue"
export default {
components: {
ComponentEvent,
Main,
ComponentA,
AttrComponents
}
}
</script>
//子组件,AttrComponents.vue组件
<template>
//必须是唯一根元素,不然不生效
<h3>透传属性</h3>
// <h3>不生效</h3> 有此标签全部不生效
</template>
<script>
export default {
inheritAttrs: false //禁止继承,上面效果不生效。
}
</script>
<style>
.attr-container {
color: red;
}
</style>
插槽Slots
父组件传递html内容(模板内容)给子组件:
//父组件
<template>
<SlotsBase> //需要传递给子组件的内容
<div>
<h3>插槽标题</h3>
<p>插槽内容</p>
</div>
</SlotsBase>
</template>
<script>
import SlotsBase from "./components/SlotsBase.vue"
export default {
components: {
SlotsBase
}
}
</script>
//子组件 SlotsBase.vue
<template>
<h3>插槽基础知识</h3>
<slot></slot> //在子组件中显示传递过来的内容
</template>
官方描述:
传递动态数据和插槽默认值:
//父组件
<template>
<SlotsTow>
<h3>{{ message }}</h3> //动态数据
</SlotsTow>
</template>
<script>
import SlotsTow from "./components/SlotsTow.vue"
export default {
data() {
return {
message: "插槽内容续集" //绑定数据需要是父组件中
}
},
components: {
SlotsTow
}
}
</script>
//子组件SlotsTow.vue
<template>
<h3>Slots续集</h3>
<slot>插槽默认值</slot> //在<slot>标签中写入值,如何父组件没有传入插槽内容,可做为默认值显示
</template>
<script>
export default {
data() {
return {
}
}
}
</script>
具名插槽,也就是按需要部分显示父组件中html内容(模板内容):
//父组件ComponentA.vue
<template>
<h3>ComponentA</h3>
<ComponentB>
<template v-slot:header> //具名插槽 v-slot可简写为#
<h3>标题</h3>
</template>
<template v-slot:main> //具名插槽 v-slot可简写为#
<p>内容</p>
</template>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data() {
return {
message: "message在父级"
}
},
components: {
ComponentB
}
}
</script>
//子组件ComponentB.vue
<template>
<h3>ComponentB</h3>
<slot name="header"></slot> //使用
<hr>
<slot name="main"></slot> //使用
</template>
插槽中的数据传递(有时候也需要将子组件中定义的数据显示在插槽中):
//父组件
<template>
<h3>ComponentA</h3>
<ComponentB v-slot="slotProps"> //父组件会用固定名字slotProps对象接收子组件的数据
<h3>{{ message }}-{{ slotProps.text }}</h3> //slotProps.text
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data() {
return {
message: "message在父级"
}
},
components: {
ComponentB
}
}
</script>
//子组件
<template>
<h3>ComponentB</h3>
<slot :text="message"></slot> //将子组件中定义的数据message传给父组件
</template>
<script>
export default {
data() {
return {
message: "ComponentB中的数据"
}
}
}
</script>
如果是具名插槽数据传递这么操作:
//父组件
<template>
<h3>ComponentA</h3>
<ComponentB>
<template #header = "slotProps" //这样操作
<h3>{{ message }}-{{ slotProps.text }}</h3>
<template>
<template #main = "slotProps"> //这样操作
<p>{{ slotPros.name }}</p>
<template>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data() {
return {
message: "message在父级"
}
},
components: {
ComponentB
}
}
</script>
//子组件
<template>
<h3>ComponentB</h3>
<slot name="header" :msg="childMessage"></slot>
<slot name="main" :name = "nameMessage"></slot>
</template>
<script>
export default {
data() {
return {
message: "ComponentB中的数据"
nameMessage:"纪舒,你好"
}
}
}
</script>
组件的生命周期
/**
* 生命周期函数
* 创建期:beforeCreate created
* 挂载期:beforeMount mounted
* 更新期:beforeUpdate updated
* 销毁期:beforeUnmount unmounted
*/
//app.vue
<template>
<h3>生命周期函数</h3>
<p>{{ message }}</p>
<button @click="message='数据'">点击</button>
</template>
<script>
export default {
data(){
return{
message:""
}
},
beforeCreate(){
console.log("beforeCreate:组件创建之前");
},
created(){
console.log("created:组件创建完成");
},
beforeMount(){
console.log("beforeMount:渲染之前");
},
mounted(){
console.log("mounted:组件渲染完成");
// 把网络请求放到这里
},
beforeUpdate(){
console.log("beforeUpdate:组件更新之前");
},
updated(){
console.log("updated:组件更新之后");
},
beforeUnmount(){
console.log("beforeUnmount:组件卸载之前");
// 卸载之前,把消耗性能的处理都干掉
// 定时器
},
unmounted(){
console.log("unmounted:组件卸载之后");
}
}
</script>
```
生命周期应用
通过ref获取元素DOM结构
<template>
<h3>组件生命周期函数应用</h3>
<p ref="name">百战程序员</p> //ref直接引用DOM元素
</template>
<script>
export default {
beforeMount() {
console.log(this.$refs.name); // undefined
},
mounted() {
console.log(this.$refs.name); //只有在挂载成功后才能访问到DOM的p标签。
}
}
</script>
模拟网络请求渲染数据
<template>
<h3>组件生命周期函数应用</h3>
<ul>
<li v-for="(item, index) of banner" :key="index">
<h3>{{ item.title }}</h3>
<p>{{ item.content }}</p>
</li>
</ul>
</template>
<script>
export default {
beforeMount() {
},
mounted() {
//模拟网络请求
//网络请求应该放在mounted里面,mounted在组件被渲染后调用。也可以放在created里面,但像京东、淘宝等网站都是先显示框架,再显示渲染数据,明显框架先显示出来更重要,建议放在mounted里面。created是data里面数据初始化后调用,beforeCreate不行,因为banner变量还没有初始化。
this.banner = [
{
"title": "我在爱尔兰",
"content": "爱尔兰(爱尔兰语:Poblacht na hÉireann;英语:Republic of Ireland),是..."
},
{
"title": "一个人的东京",
"content": "东京(Tokyo)是日本的首都,是亚洲第一大城市,世界第二大城市。全球最大的经济..."
},
{
"title": "普罗旺斯的梦",
"content": "普罗旺斯(Provence)位于法国东南部,毗邻地中海和意大利,从地中海沿岸延伸到内..."
},
{
"title": "相约夏威夷之夏",
"content": "夏威夷州位于北太平洋中,距离美国本土3,700公里,总面积16,633平方公里,属于大..."
}
]
}
}
</script>
动态组件
点击app.vue中的按钮后,让页面切换显示ComponentA和ComponentB
//ComponentA.vue
<template>
<h3>ComponentA</h3>
</template>
//ComponentB.vue
<template>
<h3>ComponentB</h3>
</template>
//app.vue
<template>
<component :is="tabComponent"></component> //需要vue自带的标签component 使用:is = 进行组件显示
<button @click="changeHandle">切换组件</button>
</template>
<script>
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"
export default {
data() {
return {
tabComponent: "ComponentA"
}
},
components: {
ComponentA,
ComponentB
},
methods: {
changeHandle() {
this.tabComponent = this.tabComponent === "ComponentA" ? "ComponentB" : "ComponentA"
}
}
}
</script>
组件保持存活
当使用component :is= 使多个组件切换时,被切换掉的组件会被卸载,也就是进入unmounted()。可以通过<keep-alive>组件强制被切换的组件仍然保持“存活”状态。
<template>
<keep-alive> //使用此标签包裹住component,可以使组件不被卸载。
<component :is="tabComponent"></component>
</keep-alive>
<button @click="changeHandle">切换组件</button>
</template>
<script>
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"
export default {
data() {
return {
tabComponent: "ComponentA"
}
},
components: {
ComponentA,
ComponentB
},
methods: {
changeHandle() {
this.tabComponent = this.tabComponent === "ComponentA" ? "ComponentB" : "ComponentA"
}
}
}
</script>
<template>
<h3>ComponentA</h3>
<p>{{ message }}</p>
<button @click="updateHandle">修改数据</button>
</template>
<script>
export default {
data() {
return {
message: "老数据"
}
},
methods: {
updateHandle() {
this.message = "新数据";
}
}
}
</script>
<template>
<h3>ComponentA</h3>
<p>{{ message }}</p>
<button @click="updateHandle">更新数据</button>
</template>
<script>
export default {
data() {
return {
message: "老数据"
}
},
beforeUnmount() {
console.log("组件卸载之前");
},
unmounted() { //组件被切换掉之后会调用这个方法
console.log("组件卸载之后");
},
methods: {
updateHandle() {
this.message = "新数据";
}
}
}
</script>
异步组件
在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue提供了defineAsyncComponent方法来实现此功能。
也就是说同步组件一般一个网站打开后,会全将全部组件从服务器请求后全部进行加载,而把一个组件定义为异步组件后,只会按需要加载,需要的时候才从服务器请求后再加载,提高运行速度。
<template>
<h3>组件切换</h3>
<keep-alive>
<component :is="currentTab"></component>
</keep-alive>
<button @click="changeComponentHandle">切换</button>
</template>
<script>
import { defineAsyncComponent } from 'vue' //引入
import ComponentA from "./components/ComponentA.vue"
const AsyncComponentB = defineAsyncComponent(() => //定义为异步组件
import('./components/ComponentB.vue')
)
export default {
components: {
ComponentA,
AsyncComponentB
},
data() {
return {
currentTab: "ComponentA",
}
},
methods: {
changeComponentHandle() {
this.currentTab = this.currentTab === "ComponentA" ? "AsyncComponentB" : "ComponentA"
}
}
<script/>
依赖注入
通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props。想象一下这样的结构:有一些多层级嵌套的组件,形成了一颗巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦。
provide和inject可以帮助我们解决这一问题。一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
//app.vue
<template>
<h3>祖宗</h3>
<Parent/>
</template>
<script>
import Parent from "./components/Parent.vue"
export default {
data() {
return {
message: "爷爷的财产!!!"
}
},
// provide: {
// message: "爷爷的财产" //传递字串符
// },
provide() { //传递变量数据
return {
message: this.message
}
},
components: {
Parent
}
}
</script>
//Parent.vue
<template>
<h3>Parent</h3>
<Child />
</template>
<script>
import Child from "./Child.vue"
export default {
components: {
Child
}
}
</script>
//Child.vue
<template>
<h3>Child</h3>
<p>{{ message }}</p>
<p>{{ fullMessage }}</p>
<p>{{ golabData }}</p>
</template>
<script>
export default {
inject: ["message","golabData"], //inject接收数据
data() {
return {
fullMessage: this.message //也可传递给data变量使用
}
}
}
</script>
//main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.provide("goLabData", "我是全局数据") //全局传递goLabData变量,全局可接收
app.mount('#app')
注意:provide和inject只能由上到下的传递,不能反向传递。
vue应用
这段讲的是整个vue项目各个文件、文件夹都是什么。
main.js 项目入口脚本
index.html 是主页。
详细看一下原视频。
vue引放路由配置
在Vue中,我们可以通过vue-router路由管理页面之间的关系
Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。
vue状态管理(Vuex)
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说,状态管理可以理解成为了更方便的管理组件之间的数据交互,提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据。
讲的简单一些就是组件之间共享变量,一个变量变动作用于所有控件。