vue-组件

221 阅读4分钟

组件

含义 可以复用的ui模块 ,一个组件对应一个实例(new Vue)

  • 组件化开发
    • 概念 将一个完整的页面抽离成一个个独立的组件=>组件是可复用的Vue实例
    • 优势 复用率高

1 注册组件

  • 1.1全局注册

    ....
    <div id="app">
    //插入组件
        <组件名></组件名>
    </div>
    ....
    //参数一:组件的名称
    //参数二:配置对象
    Vue.component('组件名',{
        //template下只能有一个根元素
        template:'<h1>我是待渲染的模板</h1>'
    })
    
  • 1.2局部注册

    ....
    <div id="app">
    //插入组件
        <组件名></组件名>
    </div>
    ....
    var vm=new Vue({
        el:'#app',
        components:{
            组件名(){
        		template:'<h1>我是待渲染的模板</h1>', 
            }
        }
    })
    
  • 组件注册的注意点

    • 全局组件注册一定要在vue实例之前
    • 不管在何种情况下template只能有一个根节点
    • 组件里的配置项和vue实例中的配置项几乎是一样的
    • 组件中的data是一个方法,并且必须要有返回值

为啥组件中的data是一个方法,而不是一个对象了?

  • 组件是一个可复用的实例
    • 组件是拿来复用的,但是,组件内的数据,是不可以共享的
    • 如果data是对象,在某个实例修改了数据,其他所有实例也会受到影响
    • data是一个函数的话,修改数据就只会影响当前实例

2组件的通讯(面试)

组件是一个独立封闭的个体

组件之间不能直接访问数据,可以通过组件的通讯来实现数据的访问

2.1父组件传值给子组件(父传子)

  • **第一步:**通过自定义属性将父组件的数据传给子组件
  • **第二步:**在子组件通过props配置项指定一下要接收的数据
    • props是一个数组,props中的数据是只读的
<div id='app'>
    //第一步
    <child :msg='pmsg'></child>
</div>

//子组件
Vue.component("child",{
    template:`<div>子组件的值:{{msg}}</div>`,
    //第二步
    props:[`msg`]
})
//父组件
const vm=new Vue({
    el:'#app',
    data:{
        pmsg:'哈哈'
    }
})

2.2子组件传值给父组件(子传父)

  • 第一步 在父组件中准备一个方法
  • 第二步,通过自定义事件将方法传递给子组件
  • 第三步 子组件调用传过来的方法(调用的时候可以传参)
<div id='app'>
    //第二步,通过自定义事件将方法传递给子组件
    <child @fn="pfn"></child>
</div>

//子组件
Vue.component("child",{
    template:`<div>子组件的值:{{msg}}</div>`,
    props:[`msg`],
    data(){
        return{
            cmsg:'子组件的数据'
        }
    },
    created(){
        //第三步 子组件调用传过来的方法
        this.$emit('fn',this.cmsg)
    }
})
//父组件
const vm=new Vue({
    el:'#app',
    methods:{
       // 第一步 在父组件中准备一个方法
        pfn(data){
            console.log("子组件里的数据是",data)
        } 
    }
})

2.3非父子之间的数据传递

  • 非父子之间的通讯是通过event bus公交车(事件总线)的机制来实现的
  • 事件总线实际上就是一个空的vue实例,事件总线可以实现任意两个组件之间的通讯,并不在意这两个组件是什么样的层级关系
  • 事件总线的过程
    • 第一步:事件总线(创建一个新的vue实例)=>var bus = new Vue()
    • 第二步:发送数据,可在点击事件里触发事件=>bus.$emit("事件名","要传递的数据")
    • 第三步:接收数据 在created钩子函数中注册事件=>bus.$on('事件名', 接收数据的参数 => {})
<div id="app">
    <jack></jack>
	<rose></rose>
<div>
    ......
// 第一步 : 事件总线
var bus = new Vue()

Vue.component('jack',{
    template:`
		<div @click='send'>我是jack</div>
`,
    methods:{
        send(){
       // 第二步 : 发送数据   可在点击事件里 触发事件
	   // 参数1 : 唯一标识  参数2:参数
            bus.$emit("love","You jump")
        }
    }
})
Vue.component('rose',{
    template:`
		<div>我是rose</div>
`,
    created(){
    // 第三步 : 接收数据    可在 created 里 注册事件
		bus.$on('love', arg => {
  			console.log('接收过来的', arg)
		})  
    }
})

3其他

3.1vue中存储属性的地方

  • **data:**可读可写,在子组件中是一个方法

  • **计算属性 (computed):**根据data中的数据变化自动计算发生改变

  • props

    • 只读

    • 不区分大小写

      1. 官 : HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。

      html 的标签和 属性 都是一样,忽略大小写 <H1 TITLE="哈哈">我是h1</H1>

      1. 官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名不好使了
      • <child :cMsg="pmsg"></child> 会报警告,父传子也接收不到了
      • 原因是 : 接收的属性是:cMsg, 接收的数据名,因为忽略大小写,数据已为 : cmsg
      • 所以已经准备要读取的 是 cmsg 的值,找不到,所以要报警告 You should probably use "c-msg" instead of "cMsg".
      1. 方式 1 : 全用小写,不要使用驼峰命名

      接收 : cmsg props/读取 :cmsg

      1. 方式 2 官 : 需要使用其等价的 kebab-case (短横线分隔命名) 命名:

      接收 : :c-msg='pmsg' props/读取 : cMsg

3.2单向数据流(组件与组件之间)

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。