Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue组件化通讯 #8

Open
huangchucai opened this issue Jun 20, 2017 · 0 comments
Open

Vue组件化通讯 #8

huangchucai opened this issue Jun 20, 2017 · 0 comments

Comments

@huangchucai
Copy link
Owner

huangchucai commented Jun 20, 2017

Vue组件化通讯

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

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

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

2. Vue的生命周期函数

  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. Vue.nextTick(callack)

    • DOM 更新循环结束之后执行延迟回调

    • 什么时候需要用到Vue.nextTick()

    1. 在 Vue 生命周期的 created() 钩子函数进行的 DOM 操作一定要放在 Vue.nextTick() 的回调函数中。原因是什么呢,原因是
      在 created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的 js 代码放进 Vue.nextTick() 的回调函数中。与之对应的就是 mounted 钩子函数,因为该钩子函数执行时所有的 DOM 挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。

    2. 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的 DOM 结构的时候,这个操作都应该放
      进 Vue.nextTick() 的回调函数中。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant