vue 之 组件 ( 重难点 )

组件(很重要很重要)

一.组件 

  • 组件可以看作是一些可复用的ui模块
    • 小到一个标签 : <div>哈哈哈</div>
    • 大到一个页面 : <div><div><div><div><div></div></div></div></div></div>
  • 一个组件对应一个实例 
  • 组件 == Vue实例 == new Vue(options)
  • 官网 : 组件是可复用的 Vue 实例

二. 组件化开发

模块开发 => 重业务,重逻辑 main,js  => router.js => handle.js => too.js

组件化开发 => 重页面/UI  头部组件  左侧栏组件   主体部分组件

  • 概念 : 将一个完整的页面抽离成一个个独立的组件,最终 , 通过这一个个独立组件完成整个的页面(项目)的功能
  • 组件化开发的优势/作用 : 复用

三. 组件的基本使用

先注册,再使用 

  • Vue 中的两种注册组件的方法 1. 全局注册 2. 局部注册
  1. 全局组件在所有的vue实例中都可以使用
  2. 局部组件在所有的当前实例中可以使用
  • 注册全局组件 - 基本使用
// 第一个参数 : 组件名 
// 第二个参数 : 是一个配置对象, 改配置对象与Vue实例的配置对象几乎完全相同
//           也就是说: vue实例中用到的配置项,和组件中的配置项几乎相同

Vue.component('child',{
    template : `
        <h1 class='red'>这是child组件</h1>
    `
})
  • 注意点
    • 注册全局组件也是放到vm实例之前
    • 模板只能有一个根节点
    • 组件的配置项和vue实例的配置项一样(如:data,methods,filters,watch,computed,钩子函数等)
    • 组件的data是一个函数,并返回一个对象
// 演示为什么vue在组件中的数据采用函数,而不是对象
// 原因 : 只想让组件复用,不想让数据复用
var Component = function() {}
// 使用对象
Component.prototype.data = {
    demo: 123
}
// 使用函数
Component.prototype.data = function() {
    return {
        demo: 111
    }
}
var component1 = new Component()
var component2 = new Component()
component1.data().demo = '8888'
console.log(component2.data().demo) // 456
  • 使用组件 ----   当标签一样使用 <child></child>

四. 组件通讯(介绍)

导入 : 演示子组件访问父组件数据,发现报错

  • 组件是一个独立.封闭的个体
    • 也就是说: 组件中的数据默认情况下,只能在组件内部使用,无法直接在组件外部使用
    • 可以将vue实例看做一个组件
  • 对于组件之间需要相互使用彼此的情况,应该使用 组件通讯 机制  来解决
  • 组件通讯的三种情况 :
  1. 父组件将数据传递给子组件(父 -> 子)
  2. 子组件将数据传递给父组件(子 -> 父)
  3. 非父子组件(兄弟组件)

五. 父 ===> 子 (重点)  两步

  1. 通过属性 ,父组件将要传递的数据,传递给子组件
    <child :msg="pmsg"></child>
  2. 子组件通过props配置项,来指定要接收的数据
    props:['msg']
    // 以后使用
     - 组件内  : msg
     - 事件中  : this.msg

     

六. 子 ==> 父 ( 重点 ) 三步

1. 父组件中提供了一个方法

pfn(arg){
    consolg.log('父组件中接受到子组件传递过来的数据 : ',arg)
}

2. 通过自定义事件,父组件将这个方法传递给子组件

// 自定义事件 
<child @fn="pfn"></child>

3. 子组件调用这个方法( 触发父组件中传递过来的自定义事件 )

// 在钩子函数里样式也可以,自己调用 
created(){
    // 调用父组件中的方法  pfn
    // 注意 : 通过$emit 方法来触发事件  fn
    // 第一个参数 : 便是要触发的自定义事件名称 ,也就是 @fn
    // 第二个参数 : 表示要传递给父组件的数据
    this.$emit('fn','child msg')
}

七. 目前为止存属性的地方 

  1. data : 先声明好的,再使用
  2. 计算属性
  3. props : 传递过来的
  4. 标签 : {{ msg }}   :title = 'msg'    事件 : this.msg

八. 单向数据流(组件与组件之间) (了解) 

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

  • 透漏三个问题 :
    • 组件与组件之前是单向数据流
    • 父级prop的更新回向下流动到子组件中
    • 子组件不允许修改父组件传过来的prop数据

vue  是单向的还是双向的 ? 

   双向  (v <==> M )

   单向 (组件与组件)

九: prop的特点 : 只读

  • 演示验证 props 只读
    • 传的是简单类型 : 修改会报错 
    • 传的是复杂类型(地址) : 修改不会报错,是因为地址没有变,测试 obj={ }  立马报错
    • 修改  父组件传给子组件的数据

      思路 : 把接受过来的数据保存到data中一个临时值(适用在该组件接受数据只会在当前组件内使用)

       Vue.component('child', {
              template: `
            <div>子组件 {{ cmsg }} </div>
             `,
              data() {
                return {
                  cmsg: this.msg
                }
              },
              props: ['msg'],
              created() {
                this.cmsg = 666
              }
            })

十. prop的大小写 

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

    • html 的标签和 属性 都是一样,忽略大小写

    • <H1 TITLE="哈哈">我是h1</H1>

  • 官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名不好使了

    • <child :cMsg="pmsg"></child> 会报警告,父传子也接收不到了

    • 原因是 : 接收的属性是:cMsg, 因为忽略大小写,已为 : cmsg

    • 所以已经准备要读取的 是 cmsg 的值,否则要报警告You should probably use "c-msg" instead of "cMsg".

  • 方式 1 : 全用小写,不要使用驼峰命名

    • 接收 : cmsg

    • props/读取 :cmsg

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

    • 接收 : :c-msg='pmsg'

    • props/读取 : cMsg / this.cMsg

  • 大小写在 父传子和 子传父中的应用 (都是要 带 - 的)

    • 父传子 : :c-msg ==> cMsg 改驼峰 - 因为props

    • 子传父 : @todo-head = 'pAddTodo' ==> this.$emit('todo-head') 不改驼峰

  • 完善 TodoMVC : 底部隐藏+剩余完成数+清除完成

    • 计算属性 : 已知值(todoList 在 根组件) ==> 得到一个新值(子组件里使用)

    • 父 => 子通讯

  • 番外篇 : 方法当属性传、传过来的带:得到的原型

十一. 非父子之间通讯 (组件 => )  (重点)

需求 : 组件 jack ===>  弄啥哩  ===>  组件 rose

  • 是通过  事件总线 ( event  bus  公交车 ) 的机制   来实现的
  • 事件总线 : 实际上就是一个    空Vue实例 
  • 可以实现任意两个组件之间的通讯 , 而不管两个组件到底是什么样的层级关系
  • 看图 
  • 示例 : 
// 第一步 : 事件总线  
var bus = new Vue()  

// 第二步 : 发送数据 可在点击事件里 触发事件
// 参数1 : 唯一标识    参数2 : 参数  
bus.$emit('todo','弄啥哩')


// 第三步   接受数据    可在created 里  注册事件  
bus.$on('todo',arg => {
    console.log('接受过来的',arg)
}) 

 十二 . 注册局部组件

  • 局部组件 只能在当前vue实例中使用
  • 示例 
    // 注册局部组件 : 
    conponents:{
        //child 表示组件名称
        // 值为配置对象,与 Vue.component 中的第二个参数相同
        // 注意 :子组件child属于Vue实例 , 因此 ,只能在Vue实例的模板中使用
        child:{
            templae : `
                <div>这是局部组件</div>
            `
        }
    }

十三 . 获取组件(获取DOM元素)   -- refs 

  • 说明 : vm.$refs  一个对象,持有已注册过ref的所有子组件(HTML  元素) 
  • 使用
  1. 注册   
    // $refs = { div : div元素 ,  child:child元素 }
    // 标签  
    <div ref="div">哈哈</div>
    // 组件
    <child ref="child"></child>
  2. 注意 : mounted 中的使用  
    // mounted  操作DOM 
    this.$refs.div 
    this.$refs.child
  • 注意点 : 如果获取的是一个子组件 , 那么通过 ref 就能获取到子组件中的data 和 methods 
    this.$refs.child.num
    this.$refs.child.fn
  • 场景 : 一般在第三方组件中 , 可能会用到这个功能 
  • 示例 ; 
    // 组件 
    <div ref='div'>哈哈哈</div>
    <child ref='child'></child>
    
    //js 
    mounted(){
        console.log(this.$refs.div)
        console.log(this.$refs.child.fn)
    }
发布了64 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44114310/article/details/91355505