欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

详细讲解vuecli中的vue组件化与父子通信

程序员文章站 2024-03-25 09:31:22
...

1 简介

  • vuecli 中提供一种简单的方式进行组件化开发。
  • 注意
    • 引入 js 模块和引入 vue 模块是不一样的。引入 js 模块是全局引入,而引入 vue 模块是局部引入。在不同模块下引入相同的 js 模块,当修改js模块中的变量时,会在全局影响,所有引入该模块的文件都能察觉该改动。但是修改 vue 模块中的变量,是不会影响全局的。

2 定义组件

  • 组件可以使用ES6模块化规范的写法,通过 import 引入其他vue或者js模块。
  • data 部分必须是方法而不是json对象!
<template>
  <div>
    {{msg}}
  </div>
</template>

<script>
export default {
  // 其他组件
  components: {},
  // 生命周期
  created() {},
  mounted() {},
  // vue 变量
  data() {
    return {
      msg: 'hello world',
    }
  },
  // 方法
  methods: {},
  // 来自父组件的消息
  props: {},
}
</script>

3 父组件中使用

  • 注意,子组件的名称与引入时起的名称有关与文件名无关。引入的时候必须采取驼峰命名法。标签使用的时候必须全小写,单词之间用"-"分割
  • 需要进行以下事情
    • 定义子组件的.vue文件
    • 在父组件中通过ES6模块化规范引入
    • 在 components 中注册
    • HTML代码中使用指定的标签名
// 引入
import helloWorlds from "@/views/demo1/hello-world.vue"
export default {
  name: 'Home',
  components: {
    // 注册组件
    helloWorlds
  }
}
  • HTML代码中使用
<template>
  <div class="home">
    <hello-worlds></hello-worlds>
  </div>
</template>

4 父组件和子组件沟通

4.1 (*)父组件提供对象

  • 通过传递对象来进行沟通
  • 需要做以下事情
    • 父组件中定义要传递的对象
    • 在父组件使用子组件的标签处传递该对象
    • 子组件在props中注册父组件传来的对象
  • 关于父子通信
    • 父组件传递给子组件的变量,如果在父组件中进行了修改,可以直接影响子组件
    • 子组件无法直接修改父组件传递的变量。但是父组件可以提供修改该变量的方法。
  • 这是父组件
<template>
  <div class="home">
    <hello-worlds :msg="msgInParent" :demo="demoInParent" ></hello-worlds>
  </div>
</template>

<script>
import helloWorlds from '@/views/demo1/hello-world.vue'
export default {
  name: 'Home',
  data() {
    return {
      msgInParent: '你好',
    }
  },
  methods:{
    demoInParent(){
      console.log("Home!!!")
    }
  },
  components: {
    helloWorlds,
  },
}
</script>
  • 这是子组件
    • type 可以为String 、Number、Boolean、Array、Object、Date、Function、Symbol
    • 注意,不允许子组件修改该值,但是你可以传递给子组件修改某个值的方法。
<template>
  <div>
    {{ msg }}
  </div>
</template>

<script>
export default {
  // 其他组件
  components: {},
  // 生命周期
  created() {
    this.demo()
  },
  mounted() {},
  // vue 变量
  data() {
    return {
      
    }
  },
  // 方法
  methods: {},
  // 来自父组件的消息
  props: {
    msg: {
      type: String,
      default: '我是默认值,父组件没有传给我msg'
    },
    demo:{
      type: Function,
      default: function(){
        console.log("并没有传递进方法")
      }
    }
  },
}
</script>

4.2 父组件提供方法

  • 注意,由于方法也是对象,你可以直接使用4.1中的方法进行传递。建议只用4.1中的方法进行传递。
  • 这里提供另一种传递的方法,需要做一下事情
    • 在父组件中定义一个方法,在html代码中的子组件标签上注册该方法
    • 在子组件中可以直接使用该方法
  • 这是父组件
<template>
  <div class="home">
    <hello-worlds :msg="msgInParent" @demo-in-child="demoInParent"></hello-worlds>
  </div>
</template>

<script>
import helloWorlds from '@/views/demo1/hello-world.vue'
export default {
  name: 'Home',
  mounted() {},
  data() {
    return {
      msgInParent: '你好',
    }
  },
  methods: {
    // 被注册的方法
    demoInParent() {
      console.log('Home!!!')
    },
  },
  components: {
    helloWorlds,
  },
}
</script>
  • 这是子组件
    • 在子组件中直接使用this.$emit(‘在父组件中注册的名称’,参数列表)来调用传递过来的方法
<template>
  <div>
    {{ msg }}
  </div>
</template>

<script>
export default {
  // 其他组件
  components: {},
  // 生命周期
  created() {
    this.$emit('demo-in-child')
  },
  mounted() {},
  // vue 变量
  data() {
    return {
      
    }
  },
  // 方法
  methods: {},
  // 来自父组件的消息
  props: {
    msg: {
      type: String,
      default: '我是默认值,父组件没有传给我msg'
    },
  },
}
</script>

4.3 子组件提供对象和方法

  • 不需要子组件做额外操作,可以全权由父组件完成。
  • 注意:这里的操作会增加代码的耦合性,不建议使用这里的操作。建议使用 4.1 中的方法,让父组件提供一个对象,子组件进行修改。
  • 父组件可以直接调用子组件的方法,也可以直接修改子组件中的变量
  • 步骤
    • 需要在父组件的html代码中的子组件上绑定 ref 作为子组件的id
    • 此时子组件的对象为 this.$refs.子组件id,可通过该对象对子组件进行修改
  • 这里是父组件
<template>
  <div class="home">
    <hello-worlds ref="helloWorld"></hello-worlds>
  </div>
</template>

<script>
import helloWorlds from '@/views/demo1/hello-world.vue'
export default {
  name: 'Home',
  mounted() {
    // 调用子组件的方法console.log()
    this.$refs.helloWorld.demo()
    // 查询子组件的值
    this.$refs.helloWorld.msg = "你好"
    console.log(this.$refs.helloWorld.msg)
  },
  data() {
    return {}
  },
  methods: {},
  components: {
    helloWorlds,
  },
}
</script>
  • 这里是子组件
<template>
  <div>
    {{ msg }}
  </div>
</template>

<script>
export default {
  // 其他组件
  components: {},
  // 生命周期
  created() {},
  mounted() {},
  // vue 变量
  data() {
    return {
      msg: 'hahah',
    }
  },
  // 方法
  methods: {
    demo() {
      console.log('hello-world!!!')
    },
  },
}
</script>

5 证明导入js模块和导入vue模块的不同

5.1 导入vue模块

  • 实验思路:
    * 在两个不同的模块A和B中引入一个共用的vue模块,在模块A中修改这个共用vue模块的变量,如果在模块 B 中再次查询该模块变量的时候能够察觉到被修改了,则说明是全局引入,否则是局部引入
  • 新建一个模块demo.vue
<template>
  <div>
    {{ msg }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      demodata: 1,
    }
  },
  props: {
    msg: {
      default: '我是demo',
      type: String,
    },
  },
}
</script>
  • 在两个模块中引入
    • 模块一
<template>
  <div class="home">
    <hello-worlds ref="helloWorld"></hello-worlds>
    <demo ref="demo1"></demo>
  </div>
</template>

<script>
import helloWorlds from '@/views/demo1/hello-world.vue'
import demo from '@/components/demo.vue'
export default {
  name: 'Home',
  mounted() {
    console.log(this.$refs.demo1.demodata)
    setTimeout(()=>{
      this.$refs.demo1.demodata = 2000
    },1000)
    setTimeout(()=>{
       console.log(this.$refs.demo1.demodata)
    },2000)
  },
  data() {
    return {}
  },
  methods: {},
  components: {
    helloWorlds,
    demo
  },
}
</script>
  • 模块二
<template>
  <div>
    {{ msg }}
    <br>
    <demo ref="demo1" :msg="'我是demo1——来自hello-world'"></demo>
  </div>
</template>

<script>
import demo from '@/components/demo.vue'
export default {
  // 其他组件
  components: {
    demo
  },
  // 生命周期
  created() {},
  mounted() {
    console.log(this.$refs.demo1.demodata)
    setTimeout(()=>{
       console.log(this.$refs.demo1.demodata)
    },2000)
  },
  // vue 变量
  data() {
    return {
      msg: 'hahah',
    }
  },
  // 方法
  methods: {
    demo() {
      console.log('hello-world!!!')
    },
  },
}
</script>
  • 结果是
1
1
1
2000
  • 这说明是局部引入

5.2 导入js模块

  • 实验思路
    • 在两个不同的模块A和B中引入一个共用的js模块,在模块A中修改这个共用js模块的变量,如果在模块 B 中再次查询该模块变量的时候能够察觉到被修改了,则说明是全局引入,否则是局部引入
  • js模块
export default{
  msg:15
}
  • 模块一
<template>
  <div class="home">
    <hello-worlds ref="helloWorld"></hello-worlds>
  </div>
</template>

<script>
import helloWorlds from '@/views/demo1/hello-world.vue'
import demo1Api from '@/utils/demo1.js'
export default {
  name: 'Home',
  mounted() {
    console.log(demo1Api.msg)
    setTimeout(()=>{
      console.log(demo1Api.msg)
    },2000)
  },
  data() {
    return {}
  },
  methods: {},
  components: {
    helloWorlds,
  },
}
</script>
  • 模块二
<template>
  <div>
    {{ msg }}
  </div>
</template>

<script>
import demo1Api from '@/utils/demo1.js'
export default {
  // 其他组件
  components: {},
  // 生命周期
  created() {},
  mounted() {
    console.log(demo1Api.msg)
    setTimeout(()=>{
      demo1Api.msg = 2000
    },1000)
    setTimeout(()=>{
      console.log(demo1Api.msg)
    },2000)
  },
  // vue 变量
  data() {
    return {
      
    }
  },
  // 方法
  methods: {},
  // 来自父组件的消息
  props: {
    msg: {
      type: String,
      default: '我是默认值,父组件没有传给我msg'
    },
  },
}
</script>
  • 结果是
15
15
2000
2000
  • 这意味着是全局导入