【六】Vue之组件
【一】组件化开发基础
【1】组件是什么?有什么用?
组件就是:扩展 HTML 元素,
封装可重用的代码
,目的是复用
例如:有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html
组件把js,css,html放到一起,有逻辑,有样式,有html
-
组件是指系统或产品中的单个构成部分,它们可以独立存在或与其他组件进行配合,以完成特定的功能或任务。
-
在软件开发领域,组件是指可重用的、独立的、具有明确定义边界和接口的模块化部分。
-
组件的使用具有以下几个主要目的:
-
提高软件的可维护性:
- 通过使用组件,我们可以将软件系统分解为更小、更容易管理的部分,从而使得对系统的修改、升级和修复更加简洁和可控。
-
促进软件的重用:
- 组件可以被独立地开发、部署和调用,因此可以在多个项目中被重复使用,提高了开发效率。
-
提高开发速度:
- 通过使用组件,开发人员可以专注于系统的特定需求,而无需重新实现已经存在的通用功能,从而加快开发速度。
-
提高系统的可扩展性:
- 组件可以根据系统的需求进行添加、替换或移除,因此系统的功能和规模可以随着需求变化而自由扩展或调整。
-
改善代码的可读性和可理解性:
- 通过将系统划分为独立的组件,代码的结构变得更清晰,模块之间的关系更易于理解,有助于团队合作和代码维护。
-
-
总之,组件的使用可以提高软件系统的可维护性、可重用性、开发速度、可扩展性和代码质量,从而为软件开发过程带来更多的便利和效益。
【2】组件的分类:
-
全局组件:
-
全局组件是在Vue应用程序的根级别注册的组件,可以在整个应用程序的任何地方使用。
-
它们通过在Vue实例或Vue组件中进行注册,使得这些组件在整个应用程序范围内都可见并可以直接引用和调用。
-
全局组件通常用于实现应用程序中的共享组件,比如全局导航栏、页脚、弹出框等。
-
由于其在整个应用程序中的全局可见性,全局组件具有高度的重用性和灵活性。
-
-
局部组件:
- 局部组件是在Vue组件层次结构内部使用的组件。
- 它们的作用范围被限制在其所在的组件或模板内部,不具备全局的可见性。
- 局部组件通常用于实现特定组件或页面的功能和样式,可以在Vue组件的
components
选项中进行注册。 - 局部组件的设计可以帮助组织和管理代码,提高组件的复用性和可维护性。
-
功能性组件:
-
功能性组件是以功能为导向而设计的组件,通常不负责直接的用户界面展示。
-
它们主要负责执行特定的功能或处理特定的业务逻辑,例如表单验证组件、数据请求组件、路由守卫组件等。
-
功能性组件通常通过Mixin、Directives或使用Vue插件的方式进行实现。
-
-
UI 组件:
-
UI 组件是具有可见的用户界面的组件,包括按钮、输入框、滑块、选项卡等。
-
它们负责用户交互和数据展示,具有一些内置的交互行为和样式。
-
UI 组件通常通过定义模板和样式来实现,可以作为全局组件或局部组件。
-
-
容器组件:
- 容器组件是用于组织和管理其他组件的高层次组件,负责控制数据流、业务逻辑和状态管理,并将这些信息传递给其包含的子组件。
- 容器组件通常关注数据的处理和交互逻辑,比如数据列表组件、布局容器组件等。
【3】工程化开发之后:
1个组件 就是1个
xx.vue
-
在Vue工程化开发中,每一个组件通常被定义为一个以
.vue
为后缀的单文件组件(Single-File Component)。 -
这种组件定义的方式结合了模板、JS代码和CSS样式,使得组件的开发、维护和复用更加方便和清晰。
-
单文件组件(.vue)由三个主要的部分组成:
-
模板(Template):
-
模板部分使用HTML-like语法定义组件的界面结构,包括HTML标签、属性、表达式和Vue指令。
-
模板可以访问组件实例中的数据和方法,并对其进行渲染,实现最终的用户界面展示。
-
-
脚本(Script):
-
脚本部分使用JavaScript编写组件的业务逻辑,包括数据的初始化、计算属性的定义、事件处理方法的编写等。
-
脚本是组件内部逻辑的核心,它可以监听和响应外部数据变化、控制组件的行为和交互,并与其他组件进行通信。
-
-
样式(Style):
- 样式部分使用CSS预处理器(如SCSS、Less)或CSS直接编写组件的样式规则。
- 样式为组件提供了独立的样式作用域,避免样式冲突,并且可以通过CSS类绑定和动态样式绑定与组件的状态和属性进行交互。
-
-
将每一个组件定义为单个的
.vue
文件,不仅利于组件的开发和维护,也使得组件的复用和组合变得更加灵活。- 通过Vue的构建工具(如Vue CLI),可以自动地将单文件组件编译为普通的JavaScript代码,以便在浏览器中直接运行。
-
此外,工程化开发还包括了模块化、打包构建、自动化测试、代码规范等方面的内容,以提高开发效率、项目可维护性和团队协作能力。
- 这些实践通常结合使用模块打包工具(如Webpack、Rollup)和版本控制工具(如Git),帮助开发者更好地组织和管理Vue项目的代码和资源。
【二】组件的注册方式
【1】详解
- 在Vue中,组件可以通过全局注册和局部注册两种方式进行注册。
(1)全局注册:
-
全局注册是指将组件在应用程序的根实例上注册,使得该组件在整个应用中都可以被使用。
- 全局注册可以在
main.js
或类似的主入口文件中进行。
- 全局注册可以在
-
全局注册的方式如下:
// main.js
import Vue from 'vue';
import App from './App.vue';
import MyComponent from './components/MyComponent.vue';
Vue.component('my-component', MyComponent);
new Vue({
render: h => h(App),
}).$mount('#app');
- 在上述代码中,将
MyComponent
组件通过Vue.component
方法进行全局注册,注册后就可以在App.vue
中使用<my-component></my-component>
标签来引入并使用该组件。
- 注意: 全局注册的组件可以在任何地方直接使用,但也会导致组件过多时全局命名冲突的问题,因此需要谨慎使用全局注册。
(2)局部注册:
- 局部注册是指将组件在单个Vue实例或其他组件中进行注册,使得该组件仅在被注册的范围内可用。
- 局部注册的方式如下:
// App.vue
<template>
<div>
<my-component></my-component>
</div>
</template>
<script>
import MyComponent from './components/MyComponent.vue';
export default {
components: {
'my-component': MyComponent,
},
};
</script>
- 在上述代码中,将
MyComponent
组件通过components
选项进行局部注册,可以在App.vue
组件的模板中直接使用<my-component></my-component>
标签来引入并使用该组件。
- 注意: 局部注册的组件只能在其所属的Vue实例或组件内部使用,因此适合用于特定区域的组件开发和维护。
(3)其他
- 除了以上两种方式,还可以使用动态注册的方式来注册组件,即在运行时动态地将组件注册到指定的Vue实例或组件中。
- 这种方式更灵活,可以根据需要决定何时注册和注销组件。
(4)总结
- 全局注册适合大型应用中的全局共享组件
- 局部注册适合针对特定页面或组件的局部使用。
- 根据具体情况选择合适的注册方式可以更好地组织和管理Vue组件。
【2】定义全局组件,绑定事件,编写样式
(1)思路分析
- 定义全局组件、绑定事件和编写样式是Vue中使用组件的关键步骤,下面我们逐步详解每一步,并给出一个案例说明。
定义全局组件:
- 全局组件是指在整个应用程序中都可以使用的组件。
- 通常将全局组件注册在根实例中,使其在整个应用范围内可用。以下是定义全局组件的步骤:
-
在项目的入口文件(通常是
main.js
)中,导入全局组件文件。import Vue from 'vue'; import MyComponent from './components/MyComponent.vue';
-
使用
Vue.component
方法注册全局组件。Vue.component('my-component', MyComponent);
其中,
'my-component'
是组件的名称,可以根据实际需求自行命名。
绑定事件:
- 在Vue中,可以通过
v-on
指令来绑定组件的事件。以下是绑定事件的步骤:
-
在组件的模板中,使用
v-on
指令来绑定事件。<template> <button v-on:click="handleClick">Click me</button> </template>
在上述代码中,
v-on:click="handleClick"
表示当按钮被点击时,会执行handleClick
这个事件处理函数。 -
在组件的方法中,定义对应的事件处理函数。
<script> export default { methods: { handleClick() { // 事件处理逻辑 }, }, }; </script>
编写样式:
- 在Vue中,可以使用各种方法来编写组件的样式,如内联样式、组件作用域样式、CSS预处理器等。
- 以下是一些常见的方式:
-
使用内联样式:在组件的模板中,使用
style
属性来定义组件的内联样式。<template> <div :style="{ color: textColor, fontSize: '16px' }">This is a styled component</div> </template>
- 在上述代码中,
:style
表示将一个对象作为样式绑定到元素上,textColor
是从组件的数据中获取的样式值。
- 在上述代码中,
-
使用组件作用域样式:在组件的
<style>
标签中,可以编写组件的作用域样式。<template> <div class="styled-component">This is a styled component</div> </template> <style scoped> .styled-component { color: red; font-size: 16px; } </style>
- 在上述代码中,
scoped
属性表示将样式限定在当前组件的作用域范围内,不会影响其他组件或全局样式。
- 在上述代码中,
完整的案例:
<!-- MyComponent.vue -->
<template>
<div>
<button v-on:click="handleClick">Click me</button>
<div :style="{ color: textColor, fontSize: '16px' }">{{ message }}</div>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue!',
textColor: 'blue',
};
},
methods: {
handleClick() {
this.textColor = 'red';
},
},
};
</script>
<style scoped>
button {
padding: 10px;
background-color: lightblue;
border: none;
cursor: pointer;
}
.styled-component {
color: red;
font-size: 16px;
}
</style>
- 在上述案例中,我们定义了一个全局组件
MyComponent
,在模板中绑定了点击事件和样式。 - 当按钮被点击时,文本颜色将改变为红色。
- 同时,使用了作用域样式来定义按钮和文字的样式。
(2)案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>全局组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<div @click="handleClick">我是根部组件</div>
<global></global>
<ul>
<li v-for="i in 4">
<global></global>
</li>
</ul>
</div>
</body>
<script>
// 创建1个组件对象(全局组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;" @click="handleClick">我是头部组件</div>
<div v-if="isShow">显示消失</div>
</div>
`,
methods: {
handleClick() {
console.log('我被点击了')
this.isShow = !this.isShow
}
},
data() {
return {
isShow: true
}
}
})
let vm = new Vue({
el: '#box',
data: {
isShow: true
},
methods: {
handleClick() {
console.log('我被点击了 我是根组件')
}
}
})
</script>
</html>
【3】局部组件 放在 Vue实例(根组件) 中
(1)思路分析
- 局部组件是指将组件定义在Vue实例(根组件)中的一种方式。
- 下面我们逐步详解局部组件的使用方法,并给出一个案例说明。
局部组件的使用方法:
-
在Vue实例的
components
选项中定义局部组件。Vue.component('my-component', { // 组件选项 });
-
在Vue实例的模板中使用局部组件。
<template> <div> <my-component></my-component> </div> </template>
- 在上述代码中,
<my-component></my-component>
表示在Vue实例的模板中使用名为my-component
的局部组件。
- 在上述代码中,
-
在局部组件中设置组件选项。
Vue.component('my-component', { template: '<div>This is a local component</div>', // 其他组件选项 });
- 在上述代码中,
template
选项指定了局部组件的模板内容。
- 在上述代码中,
案例说明:
<!-- Main.vue -->
<template>
<div>
<h1>Welcome to my app!</h1>
<my-component></my-component>
</div>
</template>
<script>
import MyComponent from './components/MyComponent.vue';
export default {
components: {
'my-component': MyComponent,
},
};
</script>
<!-- MyComponent.vue -->
<template>
<div>
<p>This is a local component.</p>
</div>
</template>
- 在上述案例中,我们定义了一个名为
Main
的Vue实例作为根组件。- 在根组件的模板中使用了局部组件
my-component
,并将其引入到组件选项的components
属性中。
- 在根组件的模板中使用了局部组件
MyComponent
是一个局部组件,它的模板内容是一个简单的段落标签。- 当渲染
Main
组件时,my-component
会被插入到模板中,并显示出"This is a local component."的文本内容。
- 当渲染
- 通过使用局部组件,我们可以将组件的定义和使用进行封装和分离,使代码更加模块化和可维护。
(2)案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>局部组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box" style="max-width: 300px">
<local></local>
<global></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
我是全局组件
</div>
</div>
`,
})
let vm = new Vue({
el: '#box',
data: {},
// 创建1个组件对象(局部组件)
components: {
local: { // local 组件名
template: `
<div>
<div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;"
@click="handleClick">我是局部组件
</div>
</div>
`, // 组件的模板
methods: {
handleClick() {
console.log('我被点击了')
}
}
}
}
})
</script>
</html>
【4】局部组件 放在 全局组件 中
(1)思路分析
- 局部组件放在全局组件中是指将组件定义在全局组件中的一种方式。
- 下面我们逐步详解局部组件放在全局组件中的使用方法,并给出一个案例说明。
局部组件放在全局组件中的使用方法:
-
在Vue实例的
components
选项中定义全局组件,并在其中定义局部组件。Vue.component('global-component', { components: { 'local-component': { // 局部组件选项 } }, // 全局组件选项 });
-
在Vue实例的模板中使用全局组件和局部组件。
<template> <div> <global-component></global-component> </div> </template>
- 在上述代码中,
<global-component></global-component>
表示在Vue实例的模板中使用名为global-component
的全局组件,该组件中包含了一个名为local-component
的局部组件。
- 在上述代码中,
-
在局部组件中设置组件选项。
Vue.component('global-component', { components: { 'local-component': { template: '<div>This is a local component</div>', // 其他组件选项 } }, template: '<div>This is a global component</div>', // 其他组件选项 });
- 在上述代码中,
template
选项分别用于设置全局组件和局部组件的模板内容。
- 在上述代码中,
案例说明:
<!-- Main.vue -->
<template>
<div>
<h1>Welcome to my app!</h1>
<global-component></global-component>
</div>
</template>
<script>
import GlobalComponent from './components/GlobalComponent.vue';
export default {
components: {
'global-component': GlobalComponent,
},
};
</script>
<!-- GlobalComponent.vue -->
<template>
<div>
<p>This is a global component.</p>
<local-component></local-component>
</div>
</template>
<script>
import LocalComponent from './LocalComponent.vue';
export default {
components: {
'local-component': LocalComponent,
},
};
</script>
<!-- LocalComponent.vue -->
<template>
<div>
<p>This is a local component.</p>
</div>
</template>
-
在上述案例中,我们定义了一个名为
Main
的Vue实例作为根组件。- 在根组件的模板中使用了全局组件
global-component
,并将其引入到组件选项的components
属性中。
- 在根组件的模板中使用了全局组件
-
GlobalComponent
是一个全局组件,它的模板内容包含了一个段落标签和局部组件local-component
。- 在全局组件的定义中,我们通过
components
选项将局部组件引入,并给局部组件起了一个别名'local-component'
。 - 这样就可以在全局组件的模板中使用局部组件了。
- 在全局组件的定义中,我们通过
-
LocalComponent
是一个局部组件,它的模板内容也是一个简单的段落标签。 -
当渲染
Main
组件时,首先会渲染全局组件global-component
,然后在全局组件的模板中插入局部组件local-component
的内容。- 最终的渲染结果会显示出"This is a global component."和"This is a local component."的文本内容。
-
通过将局部组件放在全局组件中,我们可以更好地组织和管理组件,使代码更加清晰和可复用。
(2)案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>局部组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box" style="max-width: 300px">
<ul>
<li v-for="i in 3">
<global></global>
</li>
</ul>
</div>
</body>
<script>
// 创建1个组件对象(全局组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
我是全局的组件
</div>
<local></local>
<local></local>
<br>
</div>
`,
// 创建1个组件对象(局部组件)
components: {
local: {
template: `
<div>
<div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;">我是局部组件</div>
</div>
`,
}
}
})
let vm = new Vue({
el: '#box',
})
</script>
</html>
【5】注意事项
注意点:
- 定义的组件(body中的位置)必须要放在Vue实例(这也是一个组件 根组件)中
- 局部组件 必须放在 全局组件/根组件 中,无法单独使用
- 定义的组件必须在Vue实例的上方
(1)定义的组件必须要放在Vue实例(根组件)中:
-
组件定义的代码确实应该在Vue实例的上方。这是因为Vue组件是在Vue实例创建之前进行解析和注册的。
-
组件的定义通常位于Vue实例的前面,以确保在挂载Vue实例之前已经注册了所有的组件。
(2)局部组件必须放在全局组件/根组件中,无法单独使用:
- 局部组件确实是作为全局组件(根组件)的一部分来定义的。在Vue中,局部组件只能在包含它们的组件中使用,而不能被其他组件单独使用。
- 作为根组件的全局组件可以包含所有需要的局部组件,从而形成一个组件的层次结构。
请注意,虽然局部组件不能单独使用,但它们可以在全局组件及其子组件中多次使用。
(3)定义的组件必须在Vue实例的上方:
- 将组件定义放在Vue实例的上方是一种良好的编码习惯,有助于提高代码的可读性和可维护性。
- 通过将组件定义提前,我们可以更清晰地了解Vue实例中使用的组件,并且可以一目了然地看到整个应用程序的组件结构。
(4)综上所述
- 确保将组件定义放在Vue实例上方,并将局部组件作为全局组件(根组件)的一部分来使用,以保证Vue应用程序的正常运行和组件的层次结构。
【三】组件编写方式 与 Vue实例的区别
-
定义方式:
- Vue组件通过Vue.component() 方法进行定义,而Vue实例是通过new Vue() 构造函数来创建的。
-
作用范围:
-
每个Vue组件都有自己的作用范围,可以在组件内部定义和使用数据、方法、计算属性等。
-
而Vue实例在整个应用中拥有全局的作用范围。
-
-
复用性:
-
Vue组件是可复用的,可以在同一个应用程序的多个地方使用。
-
我们可以根据需要在应用程序中创建多个相同的组件实例。
-
而Vue实例只能创建一个,并且代表了整个应用程序的顶层实例。
-
-
组件通信:
-
Vue组件之间可以通过props和事件机制进行通信。
-
父组件可以通过props向子组件传递数据,子组件则可以通过触发事件来向父组件发送消息。
-
而Vue实例通常用于管理整个应用程序的状态和数据,并且支持全局事件总线来实现组件之间的通信。
-
-
层级关系:
- 组件之间可以形成嵌套和父子关系,也可以通过插槽(slot)机制进行内容的分发和组合。
- Vue实例则没有嵌套和父子关系的概念,它代表了整个应用程序的顶层实例。
-
总结来说
- Vue组件是Vue实例的一部分,用于实现组件化开发和代码复用,而Vue实例则是整个应用程序的顶层实例,负责管理应用程序的状态和数据。
- 组件和实例在定义方式、作用范围、复用性、通信机制和层级关系等方面都存在差异。
【1】Vue实例(其实,它也是1个组件,是1个根组件)
(1)思路分析
定义方式:
-
Vue实例是通过
new Vue()
构造函数进行创建的。 -
在构造函数中传入一个选项对象,可以定义实例的属性和方法。
-
示例:
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
methods: {
showMessage: function() {
alert(this.message);
}
}
});
作用范围:
-
Vue实例具有全局作用范围,它可以管理整个应用程序的状态和数据。
-
Vue实例负责控制应用程序的生命周期、处理用户交互和页面渲染等任务。
数据绑定:
-
Vue实例可以使用Vue的数据绑定功能,在模板中将数据和DOM元素进行关联,使得数据的变化可以实时反映在页面上。
-
示例:
<div id="app">
<p>{{ message }}</p>
<button v-on:click="showMessage">Click me</button>
</div>
组件通信:
-
Vue实例可以通过全局事件总线来实现组件之间的通信。
-
通过
$emit
触发事件和$on
监听事件,不同组件之间可以进行消息的传递和处理。 -
示例:
// 在发送方组件中触发事件
this.$emit('messageChange', 'New message');
// 在接收方组件中监听事件
this.$on('messageChange', function(newMessage) {
this.message = newMessage;
});
综上所述
- Vue实例是一个根组件,它是整个应用程序的顶层组件。
- 通过实例化Vue构造函数,并定义选项对象,我们可以创建一个Vue实例。
- Vue实例具有全局作用范围、数据绑定和组件通信等特点,用于管理应用程序的状态和数据。
- 请注意,尽管Vue实例也被称为根组件,但它与普通的组件还有一些区别
- 例如,根组件没有父组件,而普通组件可以存在嵌套和父子关系。
(2)案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<ul>
<li>字符串:{{name}}</li>
<li>数值:{{age}}</li>
<li><button @click="handleClick()">Click Here</button></li>
</ul>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
name: 'Darker',
age: 18,
},
methods: {
handleClick() {
alert('按钮被点击')
}
}
})
</script>
</html>
【2】组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>局部组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box" style="max-width: 300px">
<ul>
<li v-for="i in 3">
<global></global>
</li>
</ul>
</div>
</body>
<script>
// 创建1个组件对象(全局组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
我是全局组件
</div>
<local></local>
<br>
</div>
`,
// 创建1个组件对象(局部组件)
components: {
local: {
template: `
<div>
<div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;">我是局部组件</div>
</div>
`,
}
}
})
let vm = new Vue({
el: '#box',
})
</script>
</html>
【3】区别:
(1)自定义组件需要有1个 root element
,一般包裹在 1个div
中
(2)父子组件的data
是无法共享的
- 这一点就像Docker的容器一样,是相互隔离的
- 就算父子的data中数据相同,拥有相同的方法,也是互不影响的
(3)组件可以有data、methods、computed....,但是 data
必须是一个函数
Vue实例:data是1个键值对,用来存放属性的
var vm = new Vue({
el: '#box',
data: {
isShow: true
}
})
组件:data是1个函数,需要有返回值(return
)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;" @click="handleClick">我是头部组件</div>
<div v-if="isShow">显示消失</div>
</div>
`,
methods: {
handleClick() {
console.log('我被点击了')
this.isShow = !this.isShow
}
},
data() {
return {
isShow: true
}
}
})
【四】组件通信
【1】父传子
- 在全局组件中自定义属性:
<global :myname="name" :myage="19"></global>
- 在组件中获取:
{{myname}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- myName是自定义属性 -->
<global myname="name" myage="18"></global>
<global :myname="name" :myage="19"></global>
<global :myname="'Ben'" :myage="20"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">全局组件/子组件</div>
{{myname}}
{{myage}}
</div>
`,
props: ['myname', 'myage']
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: 'darker'
},
})
</script>
</html>
属性验证
- 限制父传子的变量类型
props: {
myname: String,
isshow: Boolean
}
- 父传子时候注意以下区别
<global :myname="name" :is_show="'false'"></global>
<global :myname="name" :is_show="false"></global>
<global :myname="name" :is_show="is_show"></global>
- 实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- myName是自定义属性 -->
<!-- <global :myname="name" :myage="19" :isshow="'false'"></global>-->
<global :my_name="name" :is_show="is_show"></global>
<global :my_name="name" :is_show="false"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">我是子组件:{{is_show}}</div>
<span>{{my_name}}</span>
</div>
`,
props: {
my_name: String,
is_show: Boolean
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: 'darker',
is_show: true
},
})
</script>
</html>
【2】子传父(通过事件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<global @my_event="handleClick($event)"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">全局组件/子组件</div>
<button @click="handleNav">点我</button>
</div>
`,
data() {
return {
name: 'Darker'
}
},
methods: {
handleNav() {
console.log('我是子组件的函数')
this.$emit('my_event', 666, 777, this.name)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {},
methods: {
handleClick(a,b,c) {
console.log('我是父组件的函数')
console.log(a)
console.log(b)
console.log(c)
}
}
})
</script>
</html>
【3】子传父(控制子组件的显示和隐藏)
- 点击子组件,就会触发父组件的某个函数执行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<global @my_event="handleClick($event)"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">全局组件/子组件</div>
<button @click="handleNav">点我</button>
</div>
`,
data() {
return {
name: 'Darker'
}
},
methods: {
handleNav() {
console.log('我是子组件的函数')
this.$emit('my_event', 666, 777, this.name)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {},
methods: {
handleClick(a,b,c) {
console.log('我是父组件的函数')
console.log(a)
console.log(b)
console.log(c)
}
}
})
</script>
</html>
【4】小案例
- 子组件有1个按钮 和 1个输入框,子组件输入完内容后,数据在父组件中展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父 小案例</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<global @my_event="handleShow($event)"></global>
<br>
<div>父组件接收到的数据:{{name}}</div>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<input type="text" v-model="myText">
<button @click="handleClick">点我传数据</button>
</div>
`,
data() {
return {
myText: ''
}
},
methods: {
handleClick() {
this.$emit('my_event', this.myText)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: ''
},
methods: {
handleShow(a) {
this.name = a
}
}
})
</script>
</html>
【5】ref属性(也可以实现组件间通信:子和父都可以实现通信)
- ref放在
标签
上,拿到的是原生的DOM节点
- ref放在
组件
上,拿到的是组件对象
,对象中的数据、函数 都可以直接使用 - 通过这种方式实现子传父(this.$refs.mychild.text)
- 通过这种方式实现父传子(调用子组件方法传参数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<input type="text" ref="myRef">
<button @click="handleButton">点我</button>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<input type="text" v-model="myText">
</div>
`,
data() {
return {
myText: ''
}
},
methods: {
handleClick() {
this.$emit('my_event', this.myText)
this.$emit('my_event', this.innerHTML)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: ''
},
methods: {
handleShow(a) {
this.name = a
},
handleButton() {
console.log(this.$refs)
console.log(this.$refs.myRef)
console.log(this.$refs.myRef.value)
}
}
})
</script>
</html>
【6】事件总线(不同层级的不同组件通信)
原本的通信方式
事件总线的通信方式
实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<global1></global1>
<hr>
<global2></global2>
</div>
</body>
<script>
// 定义1个事件总线
let bus = new Vue({})
// 组件1
Vue.component('global1', {
template: `
<div>
<h3>组件1</h3>
<input type="text" v-model="myText">
<button @click="handleClick1">点我传递数据到另一个组件</button>
</div>
`,
data() {
return {
myText: ''
}
},
methods: {
handleClick1() {
console.log(this.myText)
bus.$emit('any', this.myText) // 通过事件总线发送
}
}
})
// 组件2
Vue.component('global2', {
template: `
<div>
<h3>组件2</h3>
收到的消息是:{{recvText}}
</div>
`,
data() {
return {
recvText: ''
}
},
mounted() { // 组件的挂载(生命周期钩子函数中的1个),开始监听时间总线上的:any
bus.$on('any', (item) => {
console.log('收到了', item,)
this.recvText = item
})
},
methods: {}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {},
})
</script>
</html>
【五】动态组件
【1】详解
- Vue动态组件是Vue.js框架中的一种特性,它允许您根据不同的条件渲染不同的组件。
- 使用动态组件,您可以根据应用程序状态或用户操作来切换和加载不同的组件。
- 要使用动态组件,首先需要在父组件中定义一个占位符,该占位符将根据条件动态地渲染具体的子组件。
- 这个占位符可以是一个
<component>
元素,其特殊之处在于它的is
属性将动态绑定到一个变量,用来表示要渲染的具体组件。
- 这个占位符可以是一个
- 下面是一个简单的例子,展示了如何使用动态组件:
<template>
<div>
<button @click="showComponent('ComponentA')">显示组件A</button>
<button @click="showComponent('ComponentB')">显示组件B</button>
<button @click="showComponent('ComponentC')">显示组件C</button>
<component :is="currentComponent"></component>
</div>
</template>
<script>
export default {
data() {
return {
currentComponent: null
};
},
methods: {
showComponent(component) {
this.currentComponent = component;
}
}
};
</script>
- 在上面的例子中,通过点击按钮,可以根据点击的按钮选择要渲染的具体组件。
currentComponent
变量会随着按钮的点击而改变,从而动态地切换和加载不同的子组件。
- 此外,您还可以通过使用动态组件的
keep-alive
特性,来缓存那些频繁切换的组件,以提高应用程序的性能。- 可以将
<component>
元素包裹在<keep-alive>
标签中,如下所示:
- 可以将
<template>
<div>
<button @click="showComponent('ComponentA')">显示组件A</button>
<button @click="showComponent('ComponentB')">显示组件B</button>
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>
-
这样,在切换组件时,之前渲染过的组件将会被缓存,以便稍后再次使用。
-
总结一下,Vue动态组件是一个非常有用的特性,它允许您根据条件动态地加载和切换不同的组件。
- 通过合理运用动态组件,您可以更灵活地构建您的应用程序,并提供更好的用户体验。
【2】基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动态组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<ul>
<li>
<button @click="who='child1'">首页</button>
</li>
<li>
<button @click="who='child2'">订单</button>
</li>
<li>
<button @click="who='child3'">商品</button>
</li>
</ul>
<component :is="who"></component>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
who: 'child1'
},
components: {
child1: {
template: `
<div>
<span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是首页</span>
</div>
`,
},
child2: {
template: `
<div>
<span style="border-bottom: 5px solid rgba(255,104,255,0.7)">我是订单</span>
</div>
`,
},
child3: {
template: `
<div>
<span style="border-bottom: 5px solid rgba(104,255,104,0.7)">我是商品</span>
</div>
`,
}
}
})
</script>
</html>
【3】keep-alive的使用
(1)详解
-
keep-alive
可以让输入框内有的内容一致保持,不会因为切换而重置 -
keep-alive
是Vue.js中的内置组件,它可以用来缓存动态组件。- 除了提高应用程序性能外,它还可以使组件中的输入内容保持不变,从而实现输入框内容在组件切换时的保留。
-
当一个组件被包裹在
<keep-alive>
标签中时,Vue会将该组件的状态、事件监听器以及DOM结构都进行缓存,而不是销毁和重新创建组件。- 当组件再次被渲染时,Vue会直接从缓存中取出该组件的状态和DOM结构,并将其插入到页面中,从而避免了重新渲染和初始化组件的开销。
-
由于
keep-alive
组件对组件进行缓存并保持状态,输入框中的内容不会因为组件切换而重置。- 这意味着,无论您切换到其他组件再返回,输入框中的内容仍然保持不变。
-
下面是一个示例,演示了
keep-alive
如何帮助保留输入框内容:
<template>
<div>
<input v-model="inputValue" type="text">
<button @click="toggleComponent">切换组件</button>
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>
<script>
export default {
data() {
return {
inputValue: '',
currentComponent: 'Component() {
this.currentComponent = this.currentComponent === 'ComponentA' ? 'ComponentB' : 'ComponentA';
}
}
};
</script>
- 上述示例中,有一个输入框和一个切换组件的按钮。
- 通过
v-model
将输入框的值绑定到inputValue
属性上。 - 同时,
<component>
元素通过currentComponent
属性动态渲染组件。
- 通过
- 当切换组件时,
keep-alive
会缓存之前的组件,保持其状态和DOM结构不变。- 因此,输入框中的内容会保留,不会因为组件的切换而重置。
- 通过合理使用
keep-alive
,您可以在Vue应用中实现数据的保持,提升用户体验。- 请注意,
keep-alive
并没有保护动态组件内部其他数据的变化,只是负责缓存组件的状态和DOM结构。 - 因此,在需要保证数据一致性的场景下,还需要自行处理其他数据的变化。
- 请注意,
(2)案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<ul>
<li>
<button @click="who='child1'">首页</button>
</li>
<li>
<button @click="who='child2'">订单</button>
</li>
<li>
<button @click="who='child3'">商品</button>
</li>
</ul>
<keep-alive>
<component :is="who"></component>
</keep-alive>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
who: 'child1'
},
components: {
child1: {
template: `
<div>
<span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是首页</span>
<input type="text">
</div>
`,
},
child2: {
template: `
<div>
<span style="border-bottom: 5px solid rgba(255,104,255,0.7)">我是订单</span>
<input type="text">
</div>
`,
},
child3: {
template: `
<div>
<span style="border-bottom: 5px solid rgba(104,255,104,0.7)">我是商品</span>
<input type="text">
</div>
`,
}
}
})
</script>
</html>
【六】slot 插槽
【1】详解
- 一般情况下,编写完1个组件之后,组件的内容都是写死的,需要加数据 只能去组件中修改,扩展性很差
- 然后就出现了插槽这个概念,只需在组件中添加
<slot></slot>
,就可以在body的组件标签中添加内容
- 插槽(slot)是Vue.js中的一个重要概念,它允许我们在组件的模板中定义可插入的内容,并允许使用该组件的父组件在插槽中添加具体的内容。
- 通过使用插槽,我们可以扩展组件的灵活性,使父组件能够动态地向子组件注入内容。
- 在一个组件的模板中,通过添加
<slot></slot>
标签,可以指定一个或多个插槽。- 这些插槽可以看作是占位符,用于表示将来会被传入的内容。
- 父组件可以在使用子组件时,通过特定的语法将具体的内容插入到插槽中。
- 下面是一个简单示例,演示了如何使用插槽:
<!-- 子组件 MyComponent.vue -->
<template>
<div class="my-component">
<h2>我是子组件的标题</h2>
<slot></slot>
</div>
</template>
<!-- 父组件 App.vue -->
<template>
<div class="app">
<my-component>
<p>我是插入到子组件中的内容</p>
</my-component>
</div>
</template>
- 在上述示例中,子组件
MyComponent
中包含一个插槽,通过<slot></slot>
来表示。- 父组件
App
中使用了MyComponent
,并在<my-component>
标签内插入了一个<p>
标签作为具体的内容。
- 父组件
- 当父组件和子组件进行渲染时,子组件中的插槽会被替换为父组件插入的具体内容。
- 最终的DOM结构会是:
<div class="app">
<div class="my-component">
<h2>我是子组件的标题</h2>
<p>我是插入到子组件中的内容</p>
</div>
</div>
- 通过使用插槽,我们可以将组件的具体内容交由使用组件的父组件来定义,从而提高组件的扩展性和灵活性。
- 父组件可以根据自己的需求,在插槽中添加不同的内容。
- 这使得组件能够适应多种场景,并更加通用和可复用。
- 此外,Vue还提供了具名插槽和作用域插槽等更高级的插槽用法,用于处理更复杂的组件嵌套和数据传递。
- 这些高级插槽用法可以根据实际需要进行学习和使用,以进一步发挥插槽的优势。
【2】基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>slot 插槽</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<child>
<h6>Hello World</h6>
</child>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
who: 'child1'
},
components: {
child: {
template: `
<div>
<slot></slot>
<span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是组件的原内容</span>
<slot></slot>
</div>
`,
},
}
})
</script>
</html>
【3】小案例(通过插槽实现在1个组件中控制另1个组件的显示隐藏)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>slot 插槽</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!--通过插槽实现在一个组件中控制另一个组件的显示隐藏-->
<child1>
<button @click="isShow=!isShow">显示/隐藏组件2</button>
</child1>
<child2 v-if="isShow"></child2>
</div>
</body>
<script>
Vue.component('child1', {
template: `<div>
组件1
<slot></slot>
</div>`,
})
Vue.component('child2', {
template: `<div>
<h3>组件2</h3>
</div>`,
})
var vm = new Vue({
el: '#box',
data: {
isShow: true
}
})
</script>
</html>
【4】具名插槽
(1)详解
-
具名插槽(named slots)是Vue.js中一种高级的插槽用法,它允许我们在组件的模板中定义多个具名插槽,并且可以在使用组件时,选择性地向指定的插槽中插入内容。
-
通过具名插槽,我们可以更精确地控制组件中不同部分的插入内容,提高灵活性和可复用性。下面是具名插槽的用法示例:
<!-- 子组件 MyComponent.vue -->
<template>
<div class="my-component">
<h2>我是子组件的标题</h2>
<!-- 定义具名插槽 -->
<slot name="content"></slot>
<slot name="footer"></slot>
</div>
</template>
<!-- 父组件 App.vue -->
<template>
<div class="app">
<my-component>
<!-- 插入具名插槽内容 -->
<template v-slot:content>
<p>我是插入到content插槽中的内容</p>
</template>
<template v-slot:footer>
<p>我是插入到footer插槽中的内容</p>
</template>
</my-component>
</div>
</template>
-
在上述示例中,子组件
MyComponent
中定义了两个具名插槽:content
和footer
。父组件App
在使用MyComponent
时,通过<template>
标签并使用v-slot
指令,将具体的内容插入到对应的插槽中。 -
具名插槽的写法是使用
v-slot
指令加上.key
的形式来指定插槽的名称,其中.key
可以是具体的字符串,或者是动态的表达式。 -
当父组件和子组件进行渲染时,具名插槽会根据指定的插槽名称进行匹配,并将相应的插入内容放置到对应的插槽中。最终的DOM结构会是:
<div class="app">
<div class="my-component">
<h2>我是子组件的标题</h2>
<p>我是插入到content插槽中的内容</p>
<p>我是插入到footer插槽中的内容</p>
</div>
</div>
- 通过使用具名插槽,我们可以更加精确地控制组件中不同部分的插入内容和样式,实现更细粒度的组件复用和扩展。
- 在父组件中,我们可以选择性地向指定的具名插槽中插入内容,而不必将所有内容都插入组件中。这使得组件在不同场景下具有更高的灵活性和可定制性。
(2)案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>具名插槽</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- 具名插槽,把p标签给a插槽,div标签给b插槽-->
<child>
<p slot="a">我是具名插槽a插入的内容</p>
<div slot="b">我是具名插槽b插入的内容</div>
</child>
</div>
</body>
<script>
Vue.component('child', {
template: `<div>
<slot name="a"></slot>
<hr>
<span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是组件的原内容</span>
<hr>
<slot name="b"></slot>
</div>`,
})
var vm = new Vue({
el: '#box',
data: {}
})
</script>
</html>
- 可以指定标签放在某个插槽的位置
【七】自定义组件的封装
【1】详解
- 自定义组件的封装是指在Vue.js中创建自定义组件的过程,将一些具有特定功能和样式的代码封装为可复用的组件,以提高代码的可维护性和可复用性。
- 下面是自定义组件的封装详解:
(1)创建组件文件:
- 通常情况下,我们会在项目的组件目录下创建一个新的组件文件,如
MyComponent.vue
。
(2)定义组件选项:
- 在组件文件中,我们需要通过编写Vue组件的选项来定义组件的行为、样式和模板结构。组件选项包括
template
、data
、methods
、computed
、props
等属性。
(3)组件模板:
- 在组件选项中,我们可以使用HTML和Vue的模板语法编写组件的模板。模板可以使用插值表达式、指令、事件绑定等来实现数据的动态渲染和交互。
(4)样式定义:
- 组件的封装也需要考虑组件的样式。通常,我们可以在组件选项中使用
style
标签或将样式放在单独的CSS文件中来定义组件的样式。
(5)注册组件:
-
在创建组件文件后,我们需要将组件注册到Vue应用中,以便在其他组件中使用该组件。组件的注册可以在全局或局部进行。
- 全局注册:可以通过
Vue.component
方法在应用的入口文件中进行全局注册,这样在任何组件中都可以直接使用该组件。
// 全局注册组件 Vue.component('my-component', MyComponent);
- 局部注册:也可以在需要使用该组件的父组件中进行局部注册,只在该父组件及其子组件中才能使用该组件。
// 在父组件中局部注册 import MyComponent from './MyComponent.vue'; export default { components: { 'my-component': MyComponent }, // ... }
- 全局注册:可以通过
(6)使用组件:
-
一旦组件注册完成,就可以在其他Vue组件的模板中使用该组件了。使用组件时,可以使用自定义标签的形式,并传递相应的数据和属性给组件。
<!-- 使用组件 --> <template> <div> <my-component :propName="data"></my-component> </div> </template>
(7)组件通信:
- 在自定义组件的封装过程中,还需要考虑组件之间的通信。Vue.js提供了多种方式来实现组件之间的通信,如
props
、$emit
、$on
等。通过这些方式,可以在组件之间传递数据、触发事件和监听事件。-
props
:可以通过props
属性向子组件传递数据。子组件可以通过接收props
来获取父组件传递的数据。 -
$emit
和$on
:父组件可以使用$emit
方法触发一个自定义事件,而子组件可以通过$on
方法监听这个自定义事件,并在触发时执行相应的逻辑。
-
(8)综上所述
- 自定义组件的封装是通过编写组件选项、定义组件模板和样式来创建可复用的组件,然后将其注册并在其他组件中使用。
- 同时,还需要考虑组件之间的通信方式,以实现更灵活和可复用的组件化开发。
【2】案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.css">
<script src="https://unpkg.com/swiper/swiper-bundle.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
<style>
.swiper-container {
width: 600px;
height: 200px;
}
</style>
</head>
<body>
<div id="box">
<swipper>
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="data in dataList1"><h1 style="text-align: center">{{data}}</h1></div>
</div>
</swipper>
<swipper :key="dataList2.length">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="data in dataList2"><h1 style="text-align: center">{{data}}</h1></div>
</div>
</swipper>
</div>
</body>
<script>
Vue.component('swipper', {
template: `
<div>
<div class="swiper-container">
<slot></slot>
<div class="swiper-pagination"></div>
</div>
</div>
`,
mounted() {
// 每次更新都会执行该代码,会耗费资源
let mySwiper = new Swiper('.swiper-container', {
direction: 'horizontal', // 垂直切换选项
loop: true, // 循环模式选项
// 如果需要分页器
pagination: {
el: '.swiper-pagination',
},
})
}
})
let vm = new Vue({
el: '#box',
data: {
dataList1: [],
dataList2: []
},
mounted() {
setTimeout(() => {
this.dataList1 = ['11111', '22222', '33333']
this.dataList2 = ['66666', '77777', '88888']
}, 3000)
},
})
</script>
</html>
【八】自定义指令
【1】详解
- 自定义指令是Vue.js提供的扩展能力,用于在DOM元素上添加自定义行为和功能。
- 通过自定义指令,我们可以直接操作DOM元素,监听事件,修改元素样式,绑定特定行为等。下
- 面是自定义指令的详细解释:
(1)创建指令:
- 在Vue.js中,通过
Vue.directive
方法来创建自定义指令。 - 该方法接收两个参数:
- 指令名
- 一个包含相关钩子函数的对象。
// 创建自定义指令
Vue.directive('my-directive', {
// 指令相关的钩子函数
bind(el, binding, vnode) {
// 指令绑定时调用
},
inserted(el, binding, vnode) {
// 元素插入到DOM时调用
},
update(el, binding, vnode, oldVnode) {
// 元素更新时调用
},
// ...
});
(2)钩子函数解释:
bind
: 当指令首次绑定到元素时触发。可以在此钩子函数中执行初始的设置。inserted
: 元素插入到DOM中时触发。可以在此钩子函数中执行一次性的操作,如获取焦点、滚动到指定位置等。update
: 当包含指令的组件更新时触发,可能会触发多次。可以在此钩子函数中根据更新前后的值来做响应的操作。
当然,还有其他一些指令钩子函数,如componentUpdated
、unbind
等,可以根据需要选择实现。
(3)指令对象参数解释:
el
: 指令绑定的元素,作为原生DOM对象进行操作。binding
: 一个包含指令的相关信息的对象,包括value
、arg
、modifiers
等属性。vnode
: Vue编译生成的虚拟节点。oldVnode
: 上一个虚拟节点,仅在update
钩子函数中可用。
(4)指令使用:
- 使用自定义指令时,可以通过指令名直接将指令添加到元素上。
<!-- 使用自定义指令 -->
<template>
<div>
<p v-my-directive></p>
</div>
</template>
- 在以上例子中,
<p>
标签上就会应用名为my-directive
的自定义指令。
(5)总结起来
- 自定义指令是Vue.js提供的功能强大且灵活的扩展能力,通过创建指令对象并在组件模板中应用指令名的方式,可以轻松地对DOM元素进行操作,以满足开发者的特定需求。
【2】基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自定义指令 基本使用</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<div v-mystyle>我是1个DIV</div>
</div>
</body>
<script>
// 自定义指令,使用的时候 v-自定义指令名
Vue.directive('mystyle', {
inserted(ev) { // 在标签上使用这个指令,就会触发 inserted
console.log('我执行了')
}
})
let vm = new Vue({
el: '#box'
})
</script>
</html>
【3】让所有使用自定义指令的标签背景都变红色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自定义指令 基本使用</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<div v-mystyle>我是1个DIV</div>
<br>
<div v-mystyle>我也是1个DIV</div>
</div>
</body>
<script>
// 自定义指令,使用的时候 v-自定义指令名
Vue.directive('mystyle', {
inserted(ev) { // 在标签上使用这个指令,就会触发 inserted
ev.style.background='red'
}
})
let vm = new Vue({
el: '#box'
})
</script>
</html>
【4】用户指定自定义指令的背景色,修改变量,背景变化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自定义指令</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- <div v-mystyle>我是1个DIV</div>-->
<div v-mystyle>我是1个DIV</div>
<div v-mystyle="'red'">我是1个DIV</div>
<div v-mystyle="'green'">我是1个DIV</div>
<div v-mystyle="'blue'">我是1个DIV</div>
<div v-mystyle="myColor">我是1个DIV</div>
</div>
</body>
<script>
Vue.directive('mystyle', {
inserted(ev, color) { // 这里的ev就是DOM对象
console.log(ev)
console.log(color)
ev.style.backgrond = color.value
},
updated(el, color) {
el.style.background = color.value
}
})
let vm = new Vue({
el: '#box',
data: {
myColor: 'purple'
}
})
</script>
</html>
【九】过滤器
【1】详解
- Vue过滤器是一种用于格式化、处理和转换数据的功能。
- 它们可以在模板中使用,让我们能够以一种简洁的方式对输出的数据进行处理。下面是Vue过滤器的详细解释:
(1)创建过滤器:
-
在Vue.js应用中,可以通过全局方式或局部方式创建过滤器。
-
全局过滤器:
- 使用
Vue.filter
方法来创建全局过滤器
- 使用
-
它接收两个参数:
- 过滤器名称和一个处理函数。
// 创建全局过滤器
Vue.filter('filterName', function(value) {
// 在处理函数中对数据进行处理
return processedValue;
});
-
局部过滤器:
- 在Vue组件的
filters
选项中定义局部过滤器
- 在Vue组件的
-
它也接收过滤器名称和一个处理函数。
// 在Vue组件选项中定义局部过滤器
filters: {
filterName(value) {
// 在处理函数中对数据进行处理
return processedValue;
}
}
(2)使用过滤器:
- 在模板中使用过滤器时,通过在数据后加上竖线(|)和过滤器名称的方式,将数据传递给过滤器处理。
<!-- 在模板中使用过滤器 -->
<template>
<div>
<p>{{ data | filterName }}</p>
</div>
</template>
- 在以上例子中,
data
是需要进行处理的数据,filterName
是定义的过滤器名称。
(3)过滤器参数:
- 除了数据本身之外,过滤器还可以接收额外的参数。在模板中使用过滤器时,通过冒号(:)传递参数。
<!-- 在模板中传递过滤器参数 -->
<template>
<div>
<p>{{ data | filterName(arg1, arg2) }}</p>
</div>
</template>
- 在处理函数中,可以通过在过滤器处理函数后添加形参来接收传递的参数。
(4)多个过滤器串联:
- 可以通过将多个过滤器用竖线(|)连接起来,实现多个过滤器的串联处理。
<!-- 多个过滤器串联处理 -->
<template>
<div>
<p>{{ data | filter1 | filter2 }}</p>
</div>
</template>
- 在以上例子中,
data
首先经过filter1
过滤器处理,然后再经过filter2
过滤器处理。
(5)总结起来
- Vue过滤器提供了一种方便的方式来对输出的数据进行格式化和处理。
- 通过创建过滤器并在模板中应用过滤器名称的方式,我们可以轻松地对数据进行转换和展示。
- 这样可以让我们的代码更具可读性和复用性。
【2】案例
(1)json数据:film.json
{
"coming": [
{
"id": 1240838,
"haspromotionTag": false,
"img": "http://p1.meituan.net/w.h/movie/38dd31a0e1b18e1b00aeb2170c5a65b13885486.jpg",
"version": "",
"nm": "除暴",
"preShow": false,
"sc": 8.6,
"globalReleased": true,
"wish": 76513,
"star": "王千源,吴彦祖,春夏",
"rt": "2020-11-20",
"showInfo": "今天50家影院放映79场",
"showst": 3,
"wishst": 0,
"comingTitle": "11月20日 周五"
},
{
"id": 1228788,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/movie/b16c1c0d5ac9e743c6ffbbf7eba900522725807.jpg",
"version": "",
"nm": "一秒钟",
"preShow": false,
"sc": 8.6,
"globalReleased": true,
"wish": 54493,
"star": "张译,刘浩存,范伟",
"rt": "2020-11-27",
"showInfo": "今天11家影院放映12场",
"showst": 3,
"wishst": 0,
"comingTitle": "11月27日 周五"
},
{
"id": 1358968,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/movie/d33858dbfc207da3b36c0dc7fff7a8bb2028677.jpg",
"version": "",
"nm": "汪汪队立大功之超能救援",
"preShow": false,
"sc": 8.3,
"globalReleased": true,
"wish": 24833,
"star": "杨鸥,韩娇娇,李敏妍",
"rt": "2020-11-13",
"showInfo": "今天5家影院放映7场",
"showst": 3,
"wishst": 0,
"comingTitle": "11月13日 周五"
},
{
"id": 345809,
"haspromotionTag": false,
"img": "http://p1.meituan.net/w.h/moviemachine/7c4ba9633635503044a8f8fb6426aa8d416264.jpg",
"version": "v2d imax",
"nm": "隐形人",
"preShow": false,
"sc": 8.4,
"globalReleased": true,
"wish": 9894,
"star": "伊丽莎白·莫斯,奥利弗·杰森-科恩,阿尔迪斯·霍吉",
"rt": "2020-12-04",
"showInfo": "今天21家影院放映30场",
"showst": 3,
"wishst": 0,
"comingTitle": "12月4日 周五"
},
{
"id": 1330790,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/movie/88e54f3e670789ba1f08e48a5f1170c1188102.jpg",
"version": "",
"nm": "明天你是否依然爱我",
"preShow": false,
"sc": 0,
"globalReleased": false,
"wish": 217699,
"star": "杨颖,李鸿其,黄柏钧",
"rt": "2020-12-24",
"showInfo": "2020-12-24 下周四上映",
"showst": 4,
"wishst": 0,
"comingTitle": "12月24日 周四"
},
{
"id": 1277751,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/movie/303c2e671cc4df875c151d688ecbd8962085989.jpg",
"version": "v2d imax",
"nm": "赤狐书生",
"preShow": false,
"sc": 7.7,
"globalReleased": true,
"wish": 177525,
"star": "陈立农,李现,哈妮克孜",
"rt": "2020-12-04",
"showInfo": "今天26家影院放映43场",
"showst": 3,
"wishst": 0,
"comingTitle": "12月4日 周五"
},
{
"id": 1225578,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/moviemachine/cf7d6942f2aa9189cce20519b490b6b1879487.jpg",
"version": "",
"nm": "野性的呼唤",
"preShow": false,
"sc": 9.2,
"globalReleased": true,
"wish": 14703,
"star": "哈里森·福特,丹·史蒂文斯,凯伦·吉兰",
"rt": "2020-11-13",
"showInfo": "今天暂无场次",
"showst": 3,
"wishst": 0,
"comingTitle": "11月13日 周五"
},
{
"id": 1302281,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/moviemachine/1d2b4985d0187b437d41a73994ba2e191607376.jpg",
"version": "",
"nm": "奇妙王国之魔法奇缘",
"preShow": true,
"sc": 0,
"globalReleased": false,
"wish": 20309,
"star": "卢瑶,张洋,陈新玥",
"rt": "2020-12-26",
"showInfo": "2020-12-26 下周六上映",
"showst": 4,
"wishst": 0,
"comingTitle": "12月26日 周六"
},
{
"id": 1301902,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/movie/f686425a1ad1f502254abef593d508bf428685.jpg",
"version": "",
"nm": "沉默东京",
"preShow": false,
"sc": 5.8,
"globalReleased": true,
"wish": 52,
"star": "佐藤浩市,石田百合子,西岛秀俊",
"rt": "2020-12-04",
"showInfo": "今天暂无场次",
"showst": 3,
"wishst": 0,
"comingTitle": ""
},
{
"id": 1286015,
"haspromotionTag": false,
"img": "http://p0.meituan.net/w.h/moviemachine/a0c6d6e130abe399e4cba58be2b1f871840268.jpg",
"version": "",
"nm": "宝可梦:超梦的逆袭 进化",
"preShow": false,
"sc": 8.2,
"globalReleased": true,
"wish": 53255,
"star": "松本梨香,大谷育江,市村正亲",
"rt": "2020-12-04",
"showInfo": "今天10家影院放映10场",
"showst": 3,
"wishst": 0,
"comingTitle": "12月4日 周五"
}
]
}
(2)前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>过滤器</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.min.js"></script>
</head>
<body>
<div id="box">
<ul>
<li v-for="item in dataList">
<h2>{{item.nm}}</h2>
<p>主演:{{item.star}}</p>
<img :src="item.img | repUrl" alt="">
</li>
</ul>
</div>
</body>
<script>
// 过滤器
Vue.filter('repUrl', function (url) {
return url.replace('w.h','128.180')
})
let vm = new Vue({
el: '#box',
data: {
dataList: ''
},
mounted() {
axios.get("http://127.0.0.1:5000/").then(res => {
console.log(res.data.coming)
this.dataList = res.data.coming
}).catch(err => {
console.log(err);
})
}
})
</script>
</html>
(4)后端:main.py
import json
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
print('请求来了')
with open('film.json', mode='rt', encoding='utf-8') as f:
dic = json.load(f)
res = jsonify(dic)
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()