Vue组件化开发
-
JavaScript高阶函数的使用
编程范式可以分为:命令式编程(JS)和声明式编程(Vue);或者面向对象编程(第一公民:对象)和函数式编程(第一公民:函数);
JS高级函数可以实现链式编程!!这种编程称为函数式编程;例如箭头函数,首先经过过滤,找出小于100的数值,然后将这些数值乘以2,再求取该些值得总和:
let total = nums.filter(n=> n < 100).map(n=> n*2).reduce((pre,n)=> pre+n);
filter
函数—传入参数为一个回调函数,可以循环遍历元素;
—语法:
list.filter(function(n){});
—该函数传入的回调函数有一个要求:必须返回一个布尔值;当返回
true
时,函数内部会自动将这次回调函数中的参数n加入到新的数组中;当返回false
时,回调函数会自动过滤掉该元素;例如:
<script> //可以直接实现提取出数组中小于100的元素 const nums = [10,20,111,34,201,50] let list = nums.filter(function(n){ return n<100 }) </script>
map
函数—传入参数为一个回调函数,可以循环遍历元素;
—该函数传入的回调函数会将元素或者操作处理后的元素直接返回;
例如:
<script> //返回数组元素的2倍的新数组 const nums = [10,20,30,40] let list = nums.map(function(n){ return n*2 }) </script>
reduce
函数—作用:可以实现数组中所有元素的汇总;
—需要传入两个参数为,参数一为回调函数,参数二为0,相当于初始化值为0;
—回调函数中也需要传入两个参数,参数一为前一次循环遍历返回的值(第一次循环遍历返回的值是初始化的值),参数二为循环遍历的元素值;
例如:
<script> //返回数组总和 const nums = [10,20,30,40] let sum = nums.reduce(function(preValue,n){ return preValue+n },0) //分析: //第一次 preValue:0 n:10 //第二次 preValue:0+10 n:20 //第三次 preValue: 0+10+20 n:30 //第四次 preValue: 0+10+20+30 n:40 返回0+10+20+30+40 </script>
-
组件
—基本思想:将一个页面中所有的处理逻辑全部放在一起,处理起来会比较复杂,不例如后续的管理及扩展,但是如果把页面拆分成一个个小的功能块,每个功能块完成属于自己的独立部分功能,整个页面的管理和维护就是十分容易了;
—组件化是Vue中重要的思想,它提供一抽象,让我们可以开发出一个个独立可复用的小组件构造我们的应用;任何应用都会被抽象成一颗组件树;(这里涉及到数据结构中树结构和二叉树)
注册组件的基本步骤
—创建组件构造器:调用
Vue.extend()
方法;—注册组件:调用
Vue.component()
方法;(这里是一个全局组件)—使用组件:在Vue实例的作用范围内使用组件;
—注册组件的语法糖形式,省去了
Vue.extend()
方法,直接使用一个对象代替:<script> //全局组件的注册语法糖 Vue.component('cpn',{ template:` <div> <h2>我是一个标题</h2> </div> ` }) const app = new Vue({ el:'#app', data(){ }, //局部组件的语法糖 components:{ 'cnp2':{ template:` <div>我是局部组件<div> ` } } }) </script>
组件化基本使用实例:
<div id="app"> <!--创建组件使其可复用--> <h2>我是标题</h2> <p>我是内容</p> <!--调用组件,必须在Vue实例作用的范围内才会有效果--> <my-cpn></my-cpn> </div> <script src="vue.js"></script> <script> //1. 创建组件构造对象 //ES6语法,字符串可以使用``代替"",这样在``中的内容可以进行换行 const cpnel = Vue.extend({ //传入template作为自定义组件的模板 template: `<div> <h2>我是标题</h2> <p>我是内容</p> </div>` }) //2. 注册组件 //传递两个参数,第一个是组件标签名,第二个为组件构造对象 Vue.component('my-cpn',cpnel) //Vue实例对象 const app = new Vue({ el:"#app", data:{ } }) </script>
全局组件和局部组件
—全局组件可以在多个Vue实例下使用;
—局部组件:在Vue实例中
components
属性下注册的组件即为局部组件,不可以在其他实例中使用:<script> const cpnel = Vue.extend({ //传入template作为自定义组件的模板 template: `<div> <h2>我是标题</h2> <p>我是内容</p> </div>` }) const app = new Vue({ el:"app", data:{ }, //在单个Vue实例对象下注册局部组件 component:{ //组件标签名:组件构造器 cpn:cpnel } }) </script>
父组件和子组件
—Vue可以看作是最顶层的组件,
root
组件;<script> //创建第一个组件构造器 const cpnC1 = Vue.extend({ template: `<div> <h2>我是一个标题1</h2> </div>` }) //创建第二个组件构造器 const cpnC2 = Vue.extend({ template: `<div> <h2>我是一个标题2</h2> <cpn1></cpn1> </div>`, //在组件构造器2中注册组件1,这样组件构造器2为父组件,组件构造器1为子组件 components:{ cpn1:cpnC1 } }) </script>
—父子组件的错误用法:以子标签的形式在Vue实例中使用;因为子组件注册到父组件的
compnents
时,Vue会编译好父组件的模块;该模块的内容已经决定了父组件将要渲染的页面,就相当于父组件已经有了子组件的内容了;子组件标签只能在父组件中使用;父子组件的通信
—在开发过程中,往往一些数据都是从上层传递到下层,比如一个页面从服务器请求到很多数据,其中一部分数据是需要下面子组件进行展示的,这个时候并不是让子组件在发送一个网络请求,而是直接让父组件将数据传递给子组件;
—父子间通信的两种方式:
- 父组件通过
props
向子组件传递数据; - 子组件通过自定义事件向父组件发送消息;
通过
props
向子组件传递数据方式一:字符串数组,数组中的字符串就是传递时的名称;开发中很少使用;
方式二:对象,对象可以设置传递时的类型,也可以设置默认值;
—注意,在使用
v-bind
绑定时,驼峰标识名会出错,需要进行转换,比如childMyMessage
转换为child-my-message
;—父组件通过
props
向子组件传递数据实例:<div id = "app"> <!--这里传递数据时一定要使用v-bind进行绑定--> <!--注意,在使用v-bind绑定时,驼峰标识名会出错,需要进行转换--> <cpn v-bind:c-movies="movies"></cpn> </div> <template id = "cpn"> <div> <ul> <li v-for = "item in cmovies">{{item}}</li> </ul> </div> </template> <script> const cpn = { template:'#cpn', //数组类型 props:['cmovies'], //对象形式 props:{ //可以进行类型限制,要求传递类型为数组类型 //如果类型是对象或者数组时,默认值必须是一个函数 cMovies:{ type:Array, default(){ return [] } } //可以提供默认值 cmessage:{ type:String, default:'aaaa', //要求传递数据时,必须传递cmessage内容,否则报错 required:true } }, data(){ return{} } } const app = new Vue({ el:"#app", data:{ movies:["Tom","Jack","Ammy"] }, components:{ //局部组件,对象ES6写法 cpn } }) </script>
—子组件向父组件传递数据
—当子组件向父组件传递数据时,需要用到自定义事件,
v-on
不仅可以用于监听DOM事件,也可以应用组件之间的自定义事件;<!--父组件模板--> <div id="app"> //驼峰标识需要转换 <cpn @itemclick = "cpnClick"></cpn> </div> <template id="cpn"> <div> <button v-for = "item in categories" @click = "btnClick(item)"> {{item.name}} </button> </div> </template> <script> //子组件 const cpn = { template:"#cpn", data(){ return{ categories:[ {id:'aaa',name:"热门推荐"}, {id:'bbb',name:"手机数码"}, {id:'ccc',name:"电脑办公"} ] } }, methods:{ btnClick(item){ //通过自定义事件将子组件的数据传递给父组件 // 参数为自定义事件名称和自定因 this.$emit("itemclick",item) } } } //父组件 const app = new Vue({ el:"#app", data:{ }, components:{ cpn }, methods:{ cpnClick(item){ console.log(item) } } }) </script>
组件模块分离写法
—在组件开发过程中,由于
template
模块写法太过于繁琐,我们可以将其中的HTML标签分离出来写,然后挂载到对应的组件上,使得结构变得清晰;—实现方案有两种:
- 使用
<script>
标签,注意类型必须是x-template
; - 使用
template
标签;
<!--1.使用script标签--> <script type = "text/x-template" id = "cpn"> <div> <h2>我是标题</h2> </div> </script> <!--2.使用template标签--> <template id="cpn"> <div> <h2>我是标题</h2> </div> </template> <script> Vue.component('cpn',{ template:'#cpn' }) </script>
- 父组件通过
-
组件
data
函数—组件是一个单独功能模块的封装:这个模块有属于自己的HTML模块,也有自己的属性数据
data
;—组件不能直接访问Vue实例中的
data
数据,即使可以访问,将所有数据放在Vue实例中,Vue实例会变得很臃肿;因此Vue组件应该有自己保存数据的地方。—组件对象中也有一个
data
属性(除此之外,也含有其他像methods
属性),只是这个data
属性必须是一个函数,这个函数返回一个对象,这个对象内部保存着数据;—为什么使用
data
函数,可以起到一个作用域作用,防止组件之间的数据相互调用,在创建组件时,需要重新创建并返回对象,组件之间的数据不会相互影响;<template id="cpn"> <div> <h2>当前计数:{{counter}}</h2> <button @click="increment">+</button> <button @click="decrement">-</button> <div> </template> <script> //注册组件 Vue.component('cpn',{ template:'#cpn', data(){ return { counter:0 } }, methods:{ increment(){ this.counter++ }, decrement(){ this.counter-- } } }) </script>