目录
一、组件
1. 介绍
组件 (Component) 是 Vue.js 最强大的功能之一,它是html、css、js等的一个聚合体,封装性和隔离性非常强。
组件化:
- 将一个具备完整功能的项目的一部分分割多处使用
- 加快项目的进度
- 可以进行项目的复用
组件注册分为:
全局注册和局部注册
Vue.component( id, [definition] )
参数:
{string} id
{Function | Object} [definition]
用法:
注册或获取全局组件。注册还会自动使用给定的
id
设置组件的名称// 注册组件,传入一个扩展过的构造器 Vue.component('my-component', Vue.extend({ /* ... */ })) // 注册组件,传入一个选项对象 (自动调用 Vue.extend) Vue.component('my-component', { /* ... */ }) // 获取注册的组件 (始终返回构造器) var MyComponent = Vue.component('my-component')
2. 全局组件
使用全局组件
Vue.component('组件名称', { })
,第1个参数是标签名称,第2个参数是一个选项对象。全局组件注册后,任何vue实例都可以用。必须传入template
<body> <div id="app"> <!-- 在实例中展示组件 --> <zujian></zujian> </div> </body> <script src="../js/vue.min.js"></script> <script> //定义全局组件 Vue.component('zujian', { template: "<div><div>组件中的内容1</div><div>组件中的内容2</div></div></div>", }) //创建vue实例 let vm = new Vue({ data() { return { } } }) vm.$mount('#app'); </script>
<body> <div id="app"> <div>{{str}}</div> <!-- 在实例中展示组件 --> <zujian></zujian> </div> <!--组件的视图模板中只能有一个容器 --> <template id="zujian"> <div> <div>{{str}}</div> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> /* 实例和组件之间的数据不互通 */ //定义全局组件 Vue.component('zujian', { template: "#zujian",//绑定组件的视图 //组件中的data必须使用函数式,返回一个对象 /* data函数式和data对象的区别: data对象:如果在父组件中定义数据,子组件中使用该数据并修改,会 影响父组件中原本的数据,以及其他使用该数据的子组件 data函数式:当子组件想要使用data中的数据时,父组件会单独返回 个数据给子组件,当子组件修改该数据时,对父组件原本的数据没有 影响 注意:组件中只能使用函数式 */ data() { return { str: '这是组件中的数据str' } }, }) //创建vue实例 let vm = new Vue({ data() { return { str: '这是实例中的数据str' } } }) vm.$mount('#app'); </script>
实例和组件之间的数据不互通
<body> <div id="app"> <!-- <div>{{str}}</div> --> <!-- 在实例中展示组件 --> <zujian></zujian> <hr> <zujian></zujian> </div> <!--组件的视图模板中只能有一个容器 --> <template id="zujian"> <div> <div @click="changeStr">{{str}}</div> <h3>count:{{num}}</h3> <button @click="num++">点我+++</button> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> /* 实例和组件之间的数据不互通 */ //定义全局组件 Vue.component('zujian', { template: "#zujian",//绑定组件的视图 //组件中的data必须使用函数式,返回一个对象 /* data函数式和data对象的区别: data对象:如果在父组件中定义数据,子组件中使用该数据并修改,会 影响父组件中原本的数据,以及其他使用该数据的子组件 data函数式:当子组件想要使用data中的数据时,父组件会单独返回 个数据给子组件,当子组件修改该数据时,对父组件原本的数据没有 影响 注意:组件中只能使用函数式 */ data() { return { str: '这是组件中的数据str', num: 0 } }, //组件中的普通方法 methods: { changeStr() { this.str = '这是修改后组件中的数据str' } } }) //创建vue实例 let vm = new Vue({ data() { return { str: '这是实例中的数据str' } } }) vm.$mount('#app'); </script>
组件复用
<body> <div id="app"> <!-- <div>{{str}}</div> --> <!-- 在实例中展示组件 --> <zujian2></zujian2> <hr> <zujian1></zujian1> <zujian2></zujian2> <zujian2></zujian2> </div> <!--组件的视图模板中只能有一个容器 --> <template id="zujian1"> <div> <div>{{str}}</div> </div> </template> <template id="zujian2"> <div> <div>{{str}}</div> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> /* 实例和组件之间的数据不互通 组件和组件之间的数据不互通 组件可以复用 */ //定义全局组件 Vue.component('zujian1', { template: "#zujian1",//绑定组件的视图 data() { return { str: '这是组件1中的数据str' } } }) Vue.component('zujian2', { template: "#zujian2",//绑定组件的视图 data() { return { str: '这是组件2中的数据str' } } }) //创建vue实例 let vm = new Vue({ data() { return { str: '这是实例中的数据str' } } }) vm.$mount('#app'); </script>
data函数式和data对象的区别:
- data对象:如果在父组件中定义数据,子组件中使用该数据并修改,会影响父组件中原本的数据,以及其他使用该数据的子组件
- data函数式:当子组件想要使用data中的数据时,父组件会单独返回个数据给子组件,当子组件修改该数据时,对父组件原本的数据没有影响
注意:组件中只能使用函数式data必须使用函数形式:return {}
data对象和data函数的区别
- 【data对象】:一个项目中只有一个vue实例,一个实例只对应一个id,其他的页面的内容称为组件(vuecomponent,简称vc),所有组件会继承实例,如果是data是对象的形式,当每一个组件访问实例中的data对象,修改data中的属性,其他的组件也会访问到,对象是引用数据类型,其中一个组件修改数据后就会影响其他组件及实例中的数据,造成数据混乱
- 【data函数】:return一个对象,如果每一个组件需要父组件(或实例)提供一个data中的变量,父组件(或实例)就会直接return给子组件,子组件就会得到一个单独的对象,这样就不会对其他子组件以及父组件中的数据产生影响
注意
- 实例和组件之间的数据不互通
组件和组件之间的数据不互通
组件可以复用
- 组件的视图模板中只能有一个容器
- 组件中的data必须使用函数式,返回一个对象
3. 局部组件
全局组件和局部组件的区别:
- 1.全局组件在当前项目的任何地方都可以使用,局部组件只能在当前注册的父组件中使用
- 2.全局组件适用于公共的组件,如导航栏、弹框、页脚等;局部组件适用于一些特定场景下使用的组件
局部组件(将child组件注册为实例的子组件)
通过components<body> <!-- 创建一个容器(实例的视图)--> <div id="app"> <child></child> </div> <!-- 组件的视图模板 --> <template id="child"> <div> <div>{{str}}</div> <div v-for="item in arr" :key="item"> <div>{{item}}</div> </div> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> //创建vue实例 let vm = new Vue({ data() { return { } }, //局部组件(将child组件注册为实例的子组件) components: { "child": { template: "#child",//绑定子组件的视图模板 data() {//子组件的model数据 return { str: "这是子组件中的数据", arr: ["哈哈哈", "hhh", "嘿嘿嘿"] } } } } }) //绑定实例的视图 vm.$mount("#app"); </script>
注册多个子组件(局部组件)
<body> <!-- 创建一个容器(实例的视图)--> <div id="app"> <parent></parent> <hr> <hr> <parent></parent> </div> <!-- 父组件的视图模板 --> <template id="parent"> <div> <div>{{str}}</div> <!-- 展示子组件 --> <child></child> </div> </template> <!-- 子组件的视图模板 --> <template id="child"> <div> <div>{{str}}</div> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> //父组件 Vue.component("parent", { template: "#parent", data() { return { str: "这是父组件中的数据" } }, components: { "child": { template: "#child", data() { return { str: "这是子组件中的数据" } } } } }) let vm = new Vue({ data() { return { } } }) vm.$mount("#app"); </script>
4. 父子组件的生命周期钩子函数
Vue的父子组件生命周期钩子函数的执行顺序可以清晰地分为几个阶段,包括加载渲染过程、更新过程以及销毁过程。以下是详细的解释:
加载渲染过程
- 父组件的beforeCreate:在父组件实例被创建之前调用。
- 父组件的created:在父组件实例创建完成后调用。
- 父组件的beforeMount:在父组件开始挂载之前调用,此时模板已经编译成虚拟DOM。
- 子组件的beforeCreate和created:在父组件的beforeMount钩子内,子组件的beforeCreate和created钩子依次被调用。
- 子组件的beforeMount和mounted:子组件的虚拟DOM挂载成真实DOM后,mounted钩子被调用。
- 父组件的mounted:在子组件挂载完成后,父组件的mounted钩子被调用,表示整个父组件及其子组件都已经挂载完成。
更新过程(当数据变化时)
- 父组件的beforeUpdate:在父组件的虚拟DOM重新渲染和打补丁之前调用。
- 子组件的beforeUpdate和updated:子组件根据新的数据重新渲染和更新。
- 父组件的updated:在父组件的DOM更新后调用。
销毁过程
- 父组件的beforeDestroy:在父组件销毁之前调用,用于执行清理任务。
- 子组件的beforeDestroy和destroyed:子组件在父组件销毁之前先进行销毁。
- 父组件的destroyed:父组件及其所有子组件都已经被销毁。
总结
这个顺序确保了Vue组件的层次结构在生命周期中的正确管理。在加载渲染过程中,父组件的生命周期钩子会在子组件的生命周期钩子之前触发,而在销毁过程中,子组件会先被销毁,然后才是父组件。同样,在更新过程中,父组件的更新会触发子组件的重新渲染,但父组件的更新钩子会在子组件的更新钩子之后触发。这些生命周期钩子函数顺序可以帮助开发者在合适的时机执行相应的逻辑
父子组件的生命周期钩子函数执行流程:
父组件beforecreate创建前--父组件created创建后--父组件beforeMount挂载前--子组件beforecreate创建前 --子组件created创建后 --子组件beforeMount挂载前 --子组件mounted挂载后 --父组件mounted挂载后
<body> <!-- 创建一个容器(实例的视图)--> <div id="app"> <parent></parent> </div> <!-- 父组件的视图模板 --> <template id="parent"> <div> <div>{{str}}</div> <!-- 展示子组件 --> <child></child> </div> </template> <!-- 子组件的视图模板 --> <template id="child"> <div> <div>{{str}}</div> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> //父组件 Vue.component("parent", { template: "#parent", data() { return { str: "这是父组件中的数据" } }, beforeCreate() { console.log("【父组件】创建前"); }, created() { console.log("【父组件】创建后"); }, beforeMount() { console.log("【父组件】挂载前"); }, mounted() { console.log("【父组件】挂载后"); }, components: { "child": { template: "#child", data() { return { str: "这是子组件中的数据" } }, beforeCreate() { console.log("【子组件】创建前"); }, created() { console.log("【子组件】创建后"); }, beforeMount() { console.log("【子组件】挂载前"); }, mounted() { console.log("【子组件】挂载后"); } } } }) let vm = new Vue({ data() { return { } }, beforeCreate() { console.log("【实例】创建前"); }, created() { console.log("【实例】创建后"); }, beforeMount() { console.log("【实例】挂载前"); }, mounted() { console.log("【实例】挂载后"); }, }) vm.$mount("#app"); </script>
5. 父子组件之间的数据传递
- 1.正向传递数据(父传子):vue中支持正向传递数据父组件中通过自定义属性将数据传递给子组件,子组件中通过props属性接收数据
- 2.逆向传递数据(子传父): vue中不支持逆向传递数据子组件通过$emit()方法,使用自定义监听事件向父组件传递数据
正向传递 数组
<body> <!-- 通过自定义属性传递给子组件数据 --> <div id="app"> <zujian :zifuchuan="str" :tupian="path"></zujian> </div> <!--组件的视图模板 --> <template id="zujian"> <div> <div>{{zifuchuan}}</div> <img :src="tupian"> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> let vm = new Vue({ data() { return { str: '这是实例中的数据str', path: "../img/zkt.jpg" } }, components: { "zujian": { template: "#zujian", data() { return { } }, props: ["zifuchuan", "tupian"] } } }) vm.$mount("#app"); </script>
正向传递 嵌套组件传递数据(分开传递)
HTML结构:
<div id="app">
: 这是Vue实例挂载的根DOM元素。<parent v-for="item in arr" :key="item.title" :tupian="item.imgPath" :biaoti="item.title"></parent>
: 使用v-for
指令循环遍历数组arr
中的每个项,并为每个项创建一个parent
组件实例。传递给parent
组件的属性有tupian
(图片路径)和biaoti
(标题)。Vue模板:
<template id="parent">
: 定义了一个名为parent
的Vue模板,它包含一个<div>
元素,里面有一个图片标签和一个child
组件。<template id="child">
: 定义了一个名为child
的Vue模板,它包含一个带有标题的<div>
元素。Vue脚本:
Vue.component("parent", {...})
: 定义了一个名为parent
的Vue组件,它接收tupian
和biaoti
两个属性,并注册了一个名为child
的子组件。let vm = new Vue({...})
: 创建了一个新的Vue实例,并指定了数据属性arr
,该数组包含了多个对象,每个对象包含imgPath
(图片路径)和title
(标题)属性。vm.$mount("#app");
: 将Vue实例挂载到页面上的#app
元素。
<body> <div id="app"> <parent v-for="item in arr" :key="item" :tupian="item.imgPath" :biaoti="item.title"></parent> </div> <template id="parent"> <div> <img :src="tupian" alt=""> <!-- {{biaoti}} --> <child :childtitle="biaoti"></child> </div> </template> <template id="child"> <div> <h2>{{childtitle}}</h2> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> Vue.component("parent", { template: "#parent", data() { return { } }, // 用来接收父组件传来的数据 props: ["tupian", "biaoti"], // 注册子组件 components: { "child": { template: "#child", props: ["childtitle"] } } }) let vm = new Vue({ data() { return { arr: [ { imgPath: "../img/cxk01.png", title: "图片1" }, { imgPath: "../img/cxk02.png", title: "图片2" }, { imgPath: "../img/cxk03.png", title: "图片3" } ] } } }) vm.$mount("#app"); </script>
正向传递 以对象的形式接收数据
在Vue实例中,我们使用
v-for
指令遍历arr
数组,并将每个对象传递给parent
组件。parent
组件再将接收到的对象中的title
属性传递给child
组件。最后,在child
组件中显示标题<body> <div id="app"> <parent v-for="item in arr" :key="item" :obj="item"></parent> </div> <template id="parent"> <div> <img :src="obj.imgPath" alt=""> <child :biaoti="obj.title"></child> </div> </template> <template id="child"> <div> <h2>{{biaoti}}</h2> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> Vue.component("parent", { template: "#parent", data() { return { } }, // 用来接收父组件传来的数据 props: ["obj"], // 注册子组件 components: { "child": { template: "#child", props: ["biaoti"] } } }) let vm = new Vue({ data() { return { arr: [ { imgPath: "../img/cxk01.png", title: "图片1" }, { imgPath: "../img/cxk02.png", title: "图片2" }, { imgPath: "../img/cxk03.png", title: "图片3" } ] } } }) vm.$mount("#app"); </script>
逆向传递
通过子组件 $emit( 参数 1,【参数 2】 )
参数 1:定义的事件名 参数 2:要传递的数据
子组件通过$emit()方法,使用自定义监听事件向父组件传递数据
<body> <div id="app"> <div>子组件传递过来的数据:{{ziStr}}</div> <!-- 子组件通过自定义监听事件将数据传递给父组件 --> <parent @event="fun"></parent> </div> <template id="parent"> <div> <button @click="run">子组件给父组件传递数据</button> </div> </template> </body> <script src="../js/vue.min.js"></script> <script> Vue.component("parent", { template: "#parent", data() { return { str: '这是子组件中的数据str' } }, methods: { run() { // 向上传递数据: 通过自定义监听事件传递 // $emit("事件名",要传递的真实数据) this.$emit('event', this.str); } } }) let vm = new Vue({ data() { return { ziStr: "" } }, methods: { fun(value) { console.log("value::", value); this.ziStr = value; } } }) vm.$mount("#app"); </script>
二、局部路由
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。路由实际上就是可以理解为指向,就是我在页面上点击一个按钮需要跳转到对应的页面,这就是路由跳转;
- router: 实例的路由属性
- VueRouter: Vue官方提供的路由对象
- routes: 路由的详细配置信息
首先我们来学习三个单词(route,routes,router):
1,route:首先它是个单数,译为路由,即我们可以理解为单个路由或者某一个路由;
2,routes:它是个复数,表示多个的集合才能为复数;即我们可以理解为多个路由的集合,JS中表示多种不同状态的集合的形式只有数组和对象两种,事实上官方定义routes是一个数组;所以我们记住了,routes表示多个数组的集合;
3,router:译为路由器,上面都是路由,这个是路由器,我们可以理解为一个容器包含上述两个或者说它是一个管理者,负责管理上述两个;举个常见的场景的例子:当用户在页面上点击按钮的时候,这个时候router就会去routes中去查找route,就是说路由器会去路由集合中找对应的路由;
需要导入vue-router.js 文件
<style> * { margin: 0; padding: 0; } ul { list-style: none; } #list { width: 100%; height: 50px; background-color: greenyellow; margin: 30px auto; display: flex; flex-wrap: wrap; justify-content: space-around; } #list>li { width: 30%; height: 100%; text-align: center; line-height: 50px; } </style> <body> <div id="app"> <ul id="list"> <li> <!-- router-link 代替a链接 to属性代替a链接中的href属性 --> <router-link to="/tianmao">天猫</router-link> </li> <li> <router-link to="/taobao">淘宝</router-link> </li> <li> <router-link to="/jingdong">京东</router-link> </li> </ul> <!-- router-view 路由的占位 --> <router-view></router-view> </div> <template id="tianmao"> <div> <h2>这是天猫的内容</h2> <h2>这是天猫的内容</h2> <h2>这是天猫的内容</h2> <h2>这是天猫的内容</h2> <h2>这是天猫的内容</h2> </div> </template> <template id="taobao"> <div> <h2>这是淘宝的内容</h2> <h2>这是淘宝的内容</h2> <h2>这是淘宝的内容</h2> <h2>这是淘宝的内容</h2> <h2>这是淘宝的内容</h2> </div> </template> <template id="jingdong"> <div> <h2>这是京东的内容</h2> <h2>这是京东的内容</h2> <h2>这是京东的内容</h2> <h2>这是京东的内容</h2> <h2>这是京东的内容</h2> </div> </template> </body> <script src="../js/vue.min.js"></script> <script src="../js/vue-router.js"></script> <script> let vm = new Vue({ data() { return { } }, /* router: 实例的路由属性 VueRouter: Vue官方提供的路由对象 routes: 路由的详细配置信息 */ router: new VueRouter({ routes: [ { path: "/", component: { template: "#tianmao" } }, { path: "/tianmao", component: { template: "#tianmao" } }, { path: "/taobao", component: { template: "#taobao" } }, { path: "/jingdong", component: { template: "#jingdong" } } ] }) }) vm.$mount("#app"); </script>
注意:需要使用router-view 进行路由的占位
router-link 代替a链接
to属性代替a链接中的href属性
这里不使用动态绑定 要不然运行不出来