100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Vue学习笔记之10-组件化开发

Vue学习笔记之10-组件化开发

时间:2019-11-24 07:58:32

相关推荐

Vue学习笔记之10-组件化开发

什么是组件化

将一个复杂的问题, 拆解为很多个可以处理的小问题, 再将其放到整体当中,大问题就可以迎刃而解 其实就是 动态规划问题

组件化也是类似的思想

如果将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂, 而且不利于后续的管理以及扩展, 不利于维护如果将一个页面拆分成一个个效地功能块, 每个功能块完成属于自己的部分的独立功能, 那么之后整个页面的管理和维护就变得非常容易了

组件化是Vue.js中的重要思想, 它提供了一种抽象, 让我们开发出一个个独立的可以复用的小组件来组成我们的页面

任何的应用都可以被抽象成一个组件树

组件化思想的应用

有了组件化的思想, 在以后的开发中就要充分地利用组件化尽可能地将页面拆分成一个个小的, 可以复用的组件这样可以方便代码的管理和维护,代码的扩展性也会大大增强

注册组件的基本步骤

组件的使用分成三个步骤

创建组件构造器 调用Vue.extend()方法创建组件构造器 注册组件 调用ponent()方法注册组件 使用组件 在Vue实例的作用范围内使用组件

注意: 前两个步骤代码的编写要写在 创建 new Vue() 之前

注册组件步骤解析

Vue.extend() 调用Vue.extend() 创建的是一个组件构造器在创建组件构造器的时候, 传入template 代表自定义组件的模板改模板就是在使用到组件的地方, 要显示的html代码事实上,这种写法在Vue2.x的文档中几乎看不到了,都是使用语法糖 ponent() 调用ponent() 是将创建的组件构造器注册为一个组件, 并给它一个标签名称ponent() 需要传递两个参数: 1. 注册组件的标签名 2. 组件构造器 组件必须挂载在某个Vue实例中, 否则不会生效

<div id="app"><!-- 3. 使用组件 --><my-cpn></my-cpn></div><script>// 1. 创建组件构造器const cpn = Vue.extend({template: `<div><h1>我是标题</h1><p>我是内容, 你好你好</p><p>我是内容, 你好你好</p><p>我是内容, 你好你好</p></div>`})// 2. 注册组件ponent('my-cpn', cpn)// 以上两步要写在 new Vue实例之前const app = new Vue({el: "#app",data: {}});</script>

全局组件和局部组件 (开发中常用的是局部组件)

全局组件就是在全局注册的组件, 全局组件可以在多个Vue实例中使用局部组件就是在Vue实例对象中注册的组件, 局部组件只能在当前的Vue实例下面使用, 在其他的Vue实例下使用会报错 局部组件是在Vue实例下的一个叫 components 的 option下注册的, components值是一个对象那个, 里面写入 组件名(就是在html中使用的标签名) : 组件构造器 即可注册组件 注意, 组件构造器和全局注册组件的代码要写在 创建Vue实例的代码之前

<div id="app1"><mycpn1></mycpn1><mycpn2></mycpn2></div><div id="app2"><mycpn1></mycpn1><!-- 局部的组件 在这里无效 而且会报错--><!-- <mycpn2></mycpn2> --></div><script>// 1. 创建组件构造器const cpn1 = Vue.extend({template: `<div><h2>我是标题111</h2><p>我是内容111, 你好你好</p> </div>`})const cpn2 = Vue.extend({template: `<div><h2>我是标题222</h2><p>我是内容222, 你好你好</p> </div>`})// 2. 注册组件 (全局组件)// 全局组件可以在多个Vue实例下使用ponent('mycpn1', cpn1)const app1 = new Vue({el: "#app1",// 在实例化的Vue中注册组件就是 局部组件, 局部组件只能在当前的Vue实例中使用, 不能再其他的Vue实例中使用// 在 components option中定义局部组件components: {mycpn2: cpn2 // 组件名(就是在html中使用的标签名) : 组件构造器}})const app2 = new Vue({el: "#app2"})</script>

Vue组件的父组件和子组件

子组件的注册组件代码可以写在父组件的组件构造器的名为components的option中, 子组件的注册完成后, 子组件的标签名就可以写入父组件的template中简单来说, 就是组件在哪里注册就只能在哪里使用, 浏览器解析组件标签的时候, 会先从当前的组件构造器中的components中查找是否有注册该标签名, 如果找到了就开始渲染, 如果没有找到就在全局的ponent中查找, 如果找到就渲染, 如果都没有找到的话就会报错注意, 子组件的组件构造器要写在 父组件的组件构造器之前, 否则按照浏览器解析代码的顺序, 会找不到子组件, 就会报错

<div id="app"><fathercpn></fathercpn></div><script>// 组件1const son = Vue.extend({template: `<div><h2>我是子标题</h2><p>我是子内容,呵呵呵呵</p></div>`})// 组件2// 注意, 子组件的组件构造器要写在父组件的组件构造器之前const father = Vue.extend({template: `<div><h2>我是父标题</h2><p>我是父内容,哈哈哈哈</p>在这里使用子组件<soncpn></soncpn></div>`,// 子组件可以在父组件的内部注册// 注册后就可以在父组件的template中使用components: {soncpn: son}})// 这个app可以看作是root组件(根组件)const app = new Vue({el: "#app",components: {fathercpn: father}})</script>

注册组件的语法糖

传统注册组件的方式, 有些繁琐Vue为了见过这个过程, 提供了注册的语法糖主要是省去了调用Vue.extend()的这个步骤, 可以将一个对象当作参数传入component中

<div id="app"><cpn1></cpn1><cpn2></cpn2></div><script>// 注册组件的语法糖// 1. 全局注册组件的语法糖// 将组件构造器中调用Vue.extend方法的步骤省略, 而是直接将一个对象代替传入ponent中ponent('cpn1', {template: `<div><h2>我是标题111</h2><p>我是内容111, 你好你好</p> </div>`})const app = new Vue({el: "#app",components: {// 2. 局部注册组件的语法糖// 跟全局注册组件的语法糖差不多, 也是直接将一个对象传入cpn2: {template: `<div><h2>我是标题222</h2><p>我是内容222, 你好你好</p> </div>`}}})</script>

组件模板的分离写法

template模板如果写在js代码中不优雅不好看将其中的HTML代码分离出来,然后挂载到对应的组件上Vue提供了两种方案来定义HTML模块内容 script标签 注意script标签需要定义type类型为 text/x-template并且定义id属性来绑定组件的标签名 template标签 定义id属性来绑定组件的标签名

<div id="app"><cpn1></cpn1><cpn2></cpn2></div><!-- 组件模板的分离写法 --><!-- 1. script标签写法 --><script type="text/x-template" id="cpn1"><div><h2>我是标题111</h2><p>我是内容,哈哈哈哈哈</p></div></script><!-- 2. template标签写法 --><template id="cpn2"><div><h2>我是标题222</h2><p>我是内容,呵呵呵呵呵</p></div></template><script>// 将定义的模板的id绑定到标签名中ponent('cpn1', {template: "#cpn1"})ponent('cpn2', {template: "#cpn2"})const app = new Vue({el: "#app"})</script>

组件中的数据存放问题

组件可以访问Vue中的数据吗? 不可以组件是一个单独功能模块的封装这个模块有属于自己的HTML模板, 也会有属于自己的数据data 组件中的数据是保存在自身的一个data属性中的(组件也可以有自己的methods等等option,以后会用到) 这个data属性必须是一个函数函数返回一个对象, 对象内部保存数据

<div id="app"><cpn1></cpn1></div><template id="cpn1"><div><h2>我是标题</h2><!-- 组件保存的数据也是用mustache语法引用 --><p>我是内容,{{message}}</p></div></template><script>ponent('cpn1', {template: "#cpn1",// 组件中的数据要存放在组件的注册的data中, 而且这个data必须是一个函数, 函数返回一个对象, 对象内写入数据data() {// 返回一个对象return {// 对象内写入数据message: "你好你好"}}})const app = new Vue({el: "#app"})</script>

组件中的data为什么一定要是一个对象

就是为了防止多次引用组件的时候, 组件和组件之间共用一个data, 造成变量泄露Vue已经考虑了这个问题, 所以这里必须写函数, 利用函数的作用域, 成为一个闭包, 防止变量泄露

<body><div id="app"><counter></counter><counter></counter><counter></counter></div><template id="counter"><div><h2>当前计数: {{num}}</h2><button @click="decrement">-</button><button @click="increment">+</button></div></template><script>// 1. 注册组件ponent('counter', {template: "#counter",// 这里为什么要是一个函数?// 就是为了防止多次引用组件的时候, 组件和组件之间共用一个data, 造成变量泄露// Vue已经考虑了这个问题, 所以这里必须写函数, 利用函数的作用域, 成为一个闭包, 防止变量泄露data() {return {num: 0}},methods: {increment() {this.num++},decrement() {this.num--}}})const app = new Vue({el: "#app"})</script>

组件通讯-父组件向子组件传递数据

在Vue中子组件是不可以直接引用父组件或者Vue实例中的数据的但是在开发中, 往往一些数据需要从上层传递到下层 比如在一个页面中, 从服务器请求到很多数据, 包括大组件的数据和小组件的数据, 他们都存储在大组件的data中其中一部分数据, 并非是整个页面的大组件来展示的, 而是通过子组件来展示这时, 并不会让子组件再次发送一个网络请求, 这样会大大加大服务器的压力的, 此时会让大组件(父组件)将苏剧传递给小组件(子组件) 父组件向子组件传递数据的方法 通过props向子组件传递数据 props的写法也分有数组写法和对象写法 (我们一般用对象写法)对象的写法可以设置 传入的数据类型, 是否必须传入, 默认值等等对象的写法中, 如果type的值为0的时候, 则可以传入任何类型的值

<div id="app"><!-- 传递数据要子组件的标签中用 v-bind 链接数据 --><cpn :sonmessage="message" :sonmovies="movies"></cpn></div><template id="cpn"><div><!-- 在通过子组件标签链接数据后, 就可以在子组件的html模板中用mustache语法使用数据 --><h2>{{sonmessage}}</h2><ul><li v-for="item in sonmovies">{{item}}</li></ul></div></template><script>// 这里是子组件const cpn = {template: "#cpn",// 子组件向父组件拿数据, 用props// 这里用数组形式, 数组里面传入新的数据名// props: ["sonmessage", "sonmovies"]// 这里使用对象形式, 对象形式可以设置传入的数据的类型, 默认值, 是否必须传入等等props: {// 简单地设置数据类型/* sonmessage : String,sonmovies: Array */// 传入一个对象可以有更多的操作sonmessage: {// 设置数据的类型type: String,// 设置是否必须传入required: true, // true表示必须传入, false表示不是必须传入// 设置默认值default: "你好我是默认值"},sonmovies: {type: Array,// 注意如果传入的数据类型是数组或者对象的话, 设置默认值default必须是一个函数, 函数返回一个默认的数据default () {return ["我是默认的数据", "我也是默认的数据"]}}}}const app = new Vue({el: "#app",data: {// 这里是父组件的数据message: "你好你好",movies: ["海王", "海贼王", "海尔兄弟"]},components : {cpn}})</script>

父组件向子组件传递数据时props中的驼峰标识

因为HTML代码时不区分大小写的, 所以不能使用驼峰命名法, 而JS代码时严格区分大小写的, 所以就会导致这个问题记住在HTML代码中用短线命名, 在JS代码中使用驼峰命名 就OK啦~

<div id="app"><!-- 注意这里不能使用驼峰命名法了, 要将props中的驼峰命名的转换为短线命名 --><cpn :son-message="message" :son-person="person"></cpn></div><template id="cpn"><div><!-- 这里使用的数据, 要与props中的数据名一致 --><h2>{{sonMessage}}</h2><p>{{sonPerson}}</p></div></template><script>const cpn = {template: "#cpn",props: {sonMessage: {type: String,default: "你好你好"},sonPerson: {type: Object,default () {return {}}}}}const app = new Vue({el: "#app",data: {message: "我是传入的数据",person: {name: "xiaoLam",age: 22}},components: {cpn}})</script>

子组件向父组件传递数据

需要使用自定义事件传递什么时候需要自定义事件呢? 当子组件需要向父组件传递数据的时候, 就要用到自定义事件了v-on不仅仅可以监听DOM事件, 也可以用域监听组件间的自定义事件 自定义事件的流程 在子组件中, 通过$emit()来发射数据 $emit() 中有两个参数, 第一个参数是自定义事件的名字, 第二个参数是需要发送的数据 在父组件中, 通过v-on来监听自定义事件, 接收数据

<!-- 需求: 计数器 --><!-- 操作在子组件中完成 --><!-- 展示交给父组件完成 --><!-- 父组件模版 --><div id="app"><p>{{num}}</p><!-- 在这里用v-on监听接收子组件发射数据的自定义事件 --><btn @num-de="decreNum" @num-in="increNum"></btn></div><!-- 子组件模板 --><template id="btn"><div><!-- 设置点击后触发发射数据事件 --><button @click="decrement">-</button><button @click="increment">+</button></div></template><script>// 子组件模块const btn = {template: "#btn",methods: {// 用$emit()发射数据decrement() {this.$emit("num-de")},increment() {this.$emit("num-in")}}}// 父组件模块const app = new Vue({el: "#app",data: {num: 0},components: {btn},methods: {// 处理接收来的数据increNum() {this.num++},decreNum() {this.num--}}})</script>

子组件接收来自父组件的数据, 通过子组件修改父组件的数据案例

注意!!! 子组件不要直接修改props中来自父组件的数据, 会报错的 正确做法是, 子组件修改子组件中data的数据, 然后将data中的数据通过自定义事件发送给父组件, 父组件处理接收的数据, 修改父组件自身的数据以下的代码请注意看注释以下代码实现的过程为, 从父组件通过props向子组件发送数据, 子组件接收数据, 子组件设置自己的data数据, 子组件修改自己的data数据, 子组件通过自定义事件向父组件发送自己的data数据, 父组件接收数据, 父组件修改自己的data数据, 同步修改了props向子组件发送的数据

<body><!-- 根组件模板 --><div id="app"><son :sonnum1="num1" :sonnum2="num2" @parchangenum1="parentnum1" @parchangenum2="parentnum2"></son></div><!-- 子组件模板 --><template id="son"><div><!-- 注意嗷!!! 子组件里不要直接修改props中来自父组件的数据 --><!-- <input type="number" v-model="num1"> --><input type="number" :value="num1" @input="changenum1"><!-- props 是接收的来自父组件的数据 --><h2>props : {{sonnum1}}</h2><!-- data 是子组件自身的数据 --><h2>data : {{num1}}</h2><!-- <input type="number" v-model="num2"> --><input type="number" :value="num2" @input="changenum2"><h2>props : {{sonnum2}}</h2><h2>data : {{num2}}</h2></div></template><script>const son = {template: "#son",// 接收来自根组件的数据props: {sonnum1: {// 在做这个案例的时候, 发现了一个很有趣的现象, 如果将这里的type的值设置为 0 , 那么这个sonnum1 就可以接收任何类型的数据type: Number},sonnum2: {type: Number}},// 子组件的data必须是一个函数, 防止变量泄露data() {return {num1: this.sonnum1,num2: this.sonnum2}},methods: {changenum1(event) {// 处理num1, 然后向根组件发送this.num1 = event.target.value;this.$emit("parchangenum1", this.num1);// 处理num2, 然后向根组件发送this.num2 = this.num1 * 100;this.$emit("parchangenum2", this.num2);},changenum2(event) {this.num2 = event.target.value;this.$emit("parchangenum2", this.num2)this.num1 = this.num2 / 100;this.$emit("parchangenum1", this.num1)}}}const app = new Vue({el: "#app",data: {num1: 1,num2: 2},components: {son},methods: {// 父组件处理从子组件接收来的数据parentnum1(num) {this.num1 = parseFloat(num)},parentnum2(num) {this.num2 = parseFloat(num)}}})</script></body>

组件访问-父组件访问子组件, 通过$children 和 $refs

$children 是一个数组, 里面包含的的是父组件中包含的所有子组件 想要通过children访问某一个特定的子组件只能通过数组的下标来访问(这样的方法很不灵活), 所以children访问子组件的方法很少用 $refs 是一个对象, 对象里面包含的是在父组件中 有ref属性注册的子组件, 没有ref属性的子组件不会被包含在内; 如果没有子组件设置ref属性, $refs就是一个空对象 想要通过refs访问某一个特定的子组件, 需要在子组件的ref属性设置值, 通过这个设置值来访问这个子组件

<body><div id="app"><son ref="son1"></son><son></son><son></son><!-- 通过这个按钮来触发事件 --><button @click="btnClick">按钮</button></div><template id="son"><div><h2>我是子组件</h2></div></template><script>const son = {template: "#son",data() {return {name: "子组件数据"}},methods: {showMessage() {console.log("子组件方法");}}}const app = new Vue({el: "#app",components: {son},methods: {btnClick() {// 1. 通过children获取所有的子组件// 获取的是所有的子组件组成的一个数组// 想要获取某个特定的子组件, 只能使用数组的下标获取(这样很不灵活, 所以使用children获取子组件的方法很少用)/* console.log(this.$children);this.$children[0].showMessage(); // 通过$children 使用某个下标的子组件的方法console.log(this.$children[0].name); // 通过$children 获取某个下标的子组件的数据 */// 2. 通过$refs 获取某个特定的子组件console.log(this.$refs); // $refs 获得的是一个对象, 里面包含通过标签属性ref注册的子组件 可以通过属性ref的值来获取特定的一个子组件this.$refs.son1.showMessage(); //通过refs调用ref值为son1的子组件的方法console.log(this.$refs.son1.name); // 通过refs获取ref值为son1的子组件中的数据}}})</script></body>

组件访问-子组件访问父组件, 通过$parent 和 $root

$parent 可以访问当前子组件上一级的父组件$root 可以访问当前子组件的最上级根组件这两个方法不是很常用, 因为Vue最大的优点是能够组件化分离, 如果组件用了$parent 或者 $root 方法的话就大大地减低了Vue的组件性

<body><div id="app"><son></son></div><template id="son"><div><h2>我是son组件</h2><button @click="sonBtnClick">我是son按钮</button><sonchild></sonchild></div></template><template id="sonchild"><div><h2>我是sonchild组件</h2><button @click="sonChildBtnClick">我是sonchild按钮</button></div></template><script>const app = new Vue({el: "#app",data: {message: "我是根组件的数据"},components: {son: {template: "#son",data() {return {message: "我是son组件的数据"}},methods: {sonBtnClick() {// 通过parent访问父组件console.log(this.$parent);// 通过parent访问父组件的数据console.log(this.$parent.message);}},components: {sonchild: {template: "#sonchild",methods: {sonChildBtnClick() {// 通过 $root 访问根组件console.log(this.$root);console.log(this.$root.message);// 通过$parent 访问父组件console.log(this.$parent);console.log(this.$parent.message);}}}}}}})</script></body>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。