组件化
注册组件的基本步骤
- 创建组件构造器 (调用Vue.extend()方法)
- 注册组件 (调用Vue.component()方法)
- 注册组件语法糖
- 省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替
- 注册组件语法糖
- 使用组件 (在Vue实例的作用范围内使用组件)
组件模板的分离写法
- 语法糖简化了Vue组件的注册过程,但是template模块中js和html代码混杂的写法仍让我们苦恼
于是Vue提供了两种方式,来分离模板中的js和html代码
- 使用标签 ,再通过id来关联 js <script type="text/x-template" id="cpn"> 模板内容 </script> Vue.component('cpn', { template: '#cpn' }) //全局组件
- 使用<template>
标签,再通过id来关联js <template id="cpn"> 模板内容 </template> 注册组件方式于上相同
组件可以访问Vue实例数据吗?
- 组件是一个单独功能模块的封装
- 这个模板有属于自己的HTML模板,也应该有自己的数据data
- 组件中的数据是保存再哪里呢?顶层的Vue实例中的data吗
- 通过实践,我们发现是不能访问的,即使可以,如果将所有的数据都放在Vue实例中,Vue也会变的非常臃肿
- 结论:Vue组件应该有自己保存数据的地方
- 组件中的data为什么是函数且返回对象类型?
- 为了组件的复用性和各个组件的独立性,当多次调用的时候,能为各个组件中的数据单独开辟存储空间,互补影响
父子组件的通信
- 在上面提到,子组件是不能引用父组件或者Vue实例的数据的
- 但是,在开发中,往往一些数据确实需要从上层传递到下层:
- 比如在一个页面中请求到了很多数据
- 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示
- 这时,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)/将数据传递给小组件(子组件)
- 如何进行父子间的通信呢?
- 通过props(properties:属性)向子组件传递数据(父->子)
- 通过自定义事件emit向父组件发送消息(子->父)
1父级向子级传递数据:
- 在子组件中,使用选项props来声明需要从父组件中接收到的数据(props:数组或者对象)
- 在使用子组件时通过绑定自定义属性来将数据从父组件传到子组件当中
- props驼峰标识:props定义了驼峰标识的变量数据时,在使用时要用-小写,aMessage -> a-message
- props数据验证:props使用对象可以进行数据验证和设置默认值(type,defult)
<div id='app'> <cpn :message='message'></cpn> </div> <template id="cpn"> <h2>{{ message }}</h2> </template> <script src='./vue1/js/vue.js'></script> <script> const app=new Vue({ el:'#app', data:{ message:'你好啊' }, components:{ cpn:{ template:'#cpn', props:{ message:{ type:string, defult(){ return {} } }, } } } })
2子级向父级传递数据:
- 使用自定义事件和$emit
- 通常是子组件发生了一些事件,然后告诉父组件我们发生了什么事件,并且告诉父组件对应事件的数据
<div id='app'> <cpn @itemclick='cpnclick'></cpn> </div> <template id="cpn"> <div> <button v-for="item in aaa" @click='btnclick(item)'>{{item.name}}</button> </div> </template> <script> const cpn = { template:'#cpn', data(){ return { aaa:[ {id:'aaa',name:'热门推荐'}, {id:'bbb',name:'手机数码'}, {id:'ccc',name:'家用家电'} ] } }, methods:{ btnclick(item){ //emit 发射 this.$emit('itemclick',item) } } } const app=new Vue({ el:'#app', data:{ message:'你好啊' }, components:{ cpn }, methods:{ cpnclick(item){ console.log('cpnclick',item); } } })
3父级组件访问子级组件
- 使用
$children
(通常不推荐使用)或者$refs
(refrence:引用) this.$children
是一个数组类型,它包含了所有子组件对象$refs
和ref
指令通常一起使用,首先我们通过ref给某一个子组件绑定一个特定的ID,其次,通过this.$refs.ID就可以访问到该组件了<child-cpn ref='child'></cpn> <button @click='showRefscpn'></button> showRefscpn(){ console.log(this.$refs.child.message) }
4.子级组件访问父级组件
- 可以通过$parent来实现 ,this.$parent
但是在开发中一般不会这样做,因为应该避免直接访问父组件的数据,因为这样耦合度太高了
插槽的使用(slot)
- 在子组件中使用
,就可以为子组件开启一个插槽 - 具名插槽:
<div id="app"> <cpn><span slot="center">标题</span></cpn> <cpn><button slot="left">返回</button></cpn> </div> <template id="cpn"> <div> <slot name="left"><span>左边</span></slot> <slot name="center"><span>中间</span></slot> <slot name="right"><span>右边</span></slot> </div> </template>
模块化
为什么要模块化
- 随着ajax异步请求的出现,慢慢形成了前后端的分离,客户端的代码也越来越多,为了对应代码的剧增,通常会将代码阻止在多个js文件当中,但是,这种维护方式,依然不能避免一些灾难性的问题
- 当js文件过多的时候,比如有几十个的时候,弄清楚他们的顺序是一件比较尴尬的事情
- 多个变量名冲突的问题
即使使用匿名函数解决了重名问题,但是如果讲匿名函数中的变量和方法给其他文件调用
如何模块化
模块化雏形 var moudle=(function(){ var obj={}; obj.flag=true; obj.myfunc=function(info){ console.log(info) } return obj })()
- 上面的是模块化概念的雏形,前端发展到现在,也有了很多现有的规范和对应的实现方案
- es6 :
export{}
导出 ,import{} form '文件路径'
导出- 引入时需要在上type
<script src='...' type='module'></script>
- export default + 导出成员,在导入是可以自定义命名
- 引入时需要在上type
- commonjs:
moudle.exports={xx}
导出,let={xx}=require('文件路劲')
导入 - AMD
- CMD
- es6 :