Vue组件化通讯

Vue组件化通讯

1. Vue的组成文件(.vue)

分为三部分,分别对应html,js,css

  • <template></template>
  • <script></script>
  • <style></style>

2. Vue的生命周期函数(watch的时候dom也没有更新)

  1. beforeCreate() 创建数据之前
  2. created() 创建数据 我们在这里的得到我们在data里面创建的数据
  3. beforeMount() // Dom渲染完成前
  4. mounted() //Dom渲染完成
  5. beforeUpdate() // 更新视图 在beforeUpdate触发时,视图已经更新完成
  6. Updated() //更新数据调用的函数、。
<div id='app'>
  <p>{{msg}}</p>
  <input type='text' v-model='msg'>
</div>

  
var app = new Vue({
  el: '#app',
  data() {
    return {
      msg: 1
    }
  },
  beforeCreate() {
    console.log('beforeCreate', this.msg); //beforeCreate undefined
    console.log('beforeCreate: ', document.getElementsByTagName('p')[0]) //beforeCreate <p>{{msg}}</p>
  },
  created() {
    // 创建数据
    console.log('created', this.msg); //beforeCreate 1 
    console.log('created: ', document.getElementsByTagName('p')[0]) //beforeCreate <p>{{msg}}</p>
    // 异步处理得到渲染的dom数据
    setTimeout(() => {
      this.msg = 100
      console.log('nextTick', document.getElementsByTagName('p')[0])  
    }, 100)
    // nextTick  <p>100</p>
  },
  beforeMount() {
    console.log('beforeMount', this.msg) //beforeMount 1
    console.log('beforeMount: ', document.getElementsByTagName('p')[0]) // beforeMount  <p>{{msg}}</p>
  },
  mounted() {
    // 渲染dom
    console.log('mounted', this.msg) //mounted 1
    console.log('mounted: ', document.getElementsByTagName('p')[0]) //mounted <p>1</p>
  },
  beforeUpdate() {
    console.log('beforeUpdate', this.msg) //beforeUpdate 100
    console.log('beforeUpdate: ', document.getElementsByTagName('p')[0]) //beforeUpdate <p>100</p>
  },
  updated() {
    console.log('updated', this.msg) // updated 1
    console.log('updated: ', document.getElementsByTagName('p')[0]) // updated <p>100</p>
  }
})

生命周期参考链接

3. export default

每一个模块都是自己的作用域,相应的属性来处理数据和函数

  1. data(声明数据,可以是函数和属性)
  • 类型Object | Function
  • 组件只接受函数
   // 对象的形式
   export default{
     data: {
       a:1
     }
   }
   // 函数的形式
   export default{
     data(){
       return {
         a: 1
       }
     }
   }
  1. methods(一些指令和其他属性的调用方法)
    • 不要用箭头函数来写里面的函数
    • this指向Vue的实例
 export default{
   methods: {
     plus() {
       this.a++
     }
   }
 }
  1. components (组件化定义)
    • 类型: Object
    • 自定义元素,增加代码的复用性
 // 当我们引用一个.vue文件的时候,就像使用这个文件来充当我们主体的一部分
 <div>
    <hello></hello>  
 </div>

 import hello from './hello.vue'
 export default {
   components: {
     hello
   }
 }
  1. computed(计算属性)

    • 计算属性的结果会被缓存,依赖的数据发生变化才会重新渲染
    • 注意计算属性和methods,watch的区别
    {{this.total}} //[3,4]
    <button @click='add'>添加数据</button> //点击会更新this.total    
    
    export default {
      data: () => ({
        a: 1,
        b: [2,3]
      }),
      methods: {
        add(){
          this.b.push(8);
        }
      },
      computed: {
        total(){
          return this.b.map((item)=>{
            return item+this.a
          })
        }
      }
    }
    
  2. watch(监听对应的数据)

    • 键值对。键是我们需要监督的数据,值是相应的回调函数
    • 回调函数接受2个参数,新的值和旧的值(对于数组和对象不会出现旧值,对于简单的数据会出现旧值)
    • 监听对象的内部值变化,需要添加deep:true(数组不用)
    // 点击后相应的变化
    data(){
        return {
          a: 1,
          b: [2,4,6],
          c:{name:'hcc',age:22}
        }
      },
    methods: {
       add(){
          this.a++
          this.b.push(8)
          this.c.name = 'yx'
        }
      },
    watch: {
        b: function(val, oldVal){
           console.log('new', val) //[2,4,6,8]
           console.log('new', oldVal) //[2,4,6,8]
        },
        a: function(val, oldVal){
          console.log(val);  //2
          console.log(oldVal); //1
        },
        c:{
          handler(val){
            console.log(val); //{name: 'yx',age: 22}
          } 
        }
    },
    
  3. props(用于接受父组件传来的数据)

    • 规定和接受父组件的数据
    • 单向数据流,子组件不能修改传递过来的数据
    • 对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
    • 可以规定接受的数据类型和默认值,如果是对象和数组,默认值导出是一个函数
    // 父组件
    <hello :formParent='num'></hello>  //html
    components: {
      hello
    },
    data(){
      return {
        num: 3
      }
    }
    
    //子组件
    //1. 数组规定接受的数据
    props: ['hello']
    //2. 验证的方式
    props:{
      hello: Number,
      hello: [String, Number],
      hello: {
        type: Object,
        default(){
          return {message: 'hello'}
        }
      }
    }
    
  4. v-on和v-emit(子组件向父元素传递数据)

    • vm.$emit: 子元素向父元素定义讯号和传递数据

      this.$emit('规定的讯号名称', '想传递给父元素的数据')

    • vm.$on: 监听讯号,并触发相应的函数(函数内部不用传参)

      @'规定的讯号名称'='调用自己组件的方法并可以接受传递的参数'

    // 子组件
    data () {
      return {
        msg: 'Welcome to Your Vue.js App'
      }
    },
    methods: {
      change(){
        this.$emit('sendMsg',this.msg)  //把msg传递给父组件
      }
    }
    
    // 父组件
    // 引入子组件,并定义components
    components: {
      hello
    },
    methods: {
      show(msg){     // 这里接受子组件传递的参数
        console.log(msg);
      }
    }
    
    <hello @sendMsg='show'></hello>  // 这里不用传递参数,不然会覆盖子元素传递的参数
    
  5. ref(用来获取dom和子组件)

    • 可以用来操作dom<p ref="p">hello</p>

    • 可以用来组件中的通讯

    • 在组件中使用的this.refs是一个对象,包含了所有的绑定了的dom和子组件

      // html 
       <h1 ref="myElement">这是一个dom元素</h1>  //dom元素
       <hello :propnum="propnum" :obj='d' @getson='getMsg' ref='child'></hello> // 子组件
       >-- 组件中this.refs =>  {myElement: h1, child: VueComponent}
      
      // 运用(在父元素中调用子元素的方法)
      // html 
      <hello ref='child'></hello> 
      // 子元素hello
       methods: {
         change() {
           this.$emit('getson',this.msg)
           this.obj.name = 'yx'
         },
           drop(el) {
             el.style.background = 'red';
           }
       },
         
      // 父元素
      methods: {
        add() {
          console.log(this.refs); //{child: VueComponent}
          this.$refs.child.drop('这里传递父元素的dom节点')
        }
      }
      
      //如果有一个需求是,一个父元素有2个子组件,其中一个子组件的方法要调用另一个子组件的dom元素
      1. 一个子组件需要向父组件发送元素this.$emit('方法名',dom)
      2. 父元素接受到子组件的传递得到对应dom
      3. 父元素通过this.$refs调用对应的另一个子组件的方法并传入参数
      // 子元素hello和world
        <div class="world">
          <h1 ref="world">这是world的dom元素</h1>
          <button @click='send'>给父元素传递dom</button>
        </div>
        methods: {
          send(){
            this.$emit('give',this.$refs.world); //给父元素发送dom
        }  
        <div class='hello'>
          <button>改变dom</button>
        </div>  
        methods: {
          changeDom(target){
            console.log(target)
          }
        }
          
        // 父元素
        <world @give='父亲自己的方法'></world>
        <hello ref='helloChild'></hello>
        methods: {
          // 这里接受子元素传递过来的dom元素
          '父亲自己的方法'(target) {
            this.refs.helloChild.changeDom(target)  //调用另一个子元素的方法,并把dom传递过去
          }
        }
      
  6. vm.nextTick(callback)

    • 下次dom更新循环结束后执行对应的回调函数

    • 在修改数据之后立即使用这个方法,可以获取更新后的DOM结构

  • 使用场景
    • 在 Vue 生命周期的 created() 钩子函数进行的 DOM 操作一定要放在 Vue.nextTick() 的回调函数中。原因是什么呢,原因是
      在 created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的 js 代码放进 Vue.nextTick() 的回调函数中。
      与之对应的就是 mounted 钩子函数,因为该钩子函数执行时所有的 DOM 挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
    • 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的 DOM 结构的时候,这个操作都应该放进 Vue.nextTick() 的回调函数中。
// 需求一,如果我们想异步请求数据后,在钩子函数mounted之前只用对应的dom
// 思路: 通过异步等dom更新后,然后获得对应的dom
<template>
   <h1 ref='title'>{{b}}</h1>
</template>
<script>
export default {
 data() {
      b: 'hello nextTick'
  },
  create() {
    console.log(this.refs.title)  // undefined
  }, 
// 这样可以获得对应的dom (当dom全部渲染后再执行console.log())
//  create() {
//   this.$nextTick(()=>{
//        console.log(this.refs.title);  // <h1>hello nextTick</h1>(输出在mounted的后面)
//    })
//  }, 
  mounted() {
    console.log(this.refs.title)  // <h1>hello nextTick</h1>
  }
}
</script>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容