1.组件的使用

当创建出Vue项目时,我们就已经有了一组件HelloWorld,我这里简化一下

<template>
  <div>
    <p>{{msg}}</p>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

在App.Vue中的使用

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <!-- 使用组件 -->
  <HelloWorld msg="Welcome to Your Vue.js App"/>
</template>

<script>
//引入组件
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  //组件的注册
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

使用的几个关键点就是import,以及注册

  • 父子组件

    • App.vue对于HelloWorld组件来说就是父组件,自己就是子组件
  • 全局注册和局部注册

    • 组件在当前Vue应用全局可用

      • import { createApp } from 'vue'
        import App from './App.vue'
        import HelloWorld from "@/components/HelloWorld";
        App.component('HelloWorld', HelloWorld)
        createApp(App).mount('#app')
        
    • 局部注册,只能在父组件中使用

      • 参考上面

2.组件之间的传参

父组件传子组件

子组件需要显式声明需要传入的props

举例

<template>
  <div>
    <p>{{msg}}</p>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  //这里声明
  props: {
    msg: String
  }
}
</script>

然后父组件就可以通过msg="Welcome to Your Vue.js App" 传参,或者可以传动态的:msg=message

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld :msg="message"/>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  data(){
    return{
      message:"Hello World!"
    }
  },
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
  • 传不同类型的数据

    • Boolean

      • <!-- 仅写上 prop 但不传值,会隐式转换为 `true` -->
        <BlogPost is-published />
        
        <!-- 虽然 `false` 是静态的值,我们还是需要使用 v-bind -->
        <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
        <BlogPost :is-published="false" />
        
        <!-- 根据一个变量的值动态传入 -->
        <BlogPost :is-published="post.isPublished" />
        
    • Array

      • <!-- 虽然这个数组是个常量,我们还是需要使用 v-bind -->
        <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
        <BlogPost :comment-ids="[234, 266, 273]" />
        
        <!-- 根据一个变量的值动态传入 -->
        <BlogPost :comment-ids="post.commentIds" />
        
    • Object

      • <!-- 虽然这个对象字面量是个常量,我们还是需要使用 v-bind -->
        <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
        <BlogPost
          :author="{
            name: 'Veronica',
            company: 'Veridian Dynamics'
          }"
         />
        
        <!-- 根据一个变量的值动态传入 -->
        <BlogPost :author="post.author" />
        
  • 对于父组件传来的值,子组件可以进行校验

    • Vue 组件可以更细致地声明对传入的 props 的校验要求。比如我们上面已经看到过的类型声明,如果传入的值不满足类型要求,Vue 会在浏览器控制台中抛出警告来提醒使用者。这在开发给其他开发者使用的组件时非常有用。

    • 下面是一些参数类型校验实例

      • props: {
            msg: {
              type: String,
              default: 'Hello',
              required:true
            },
            book:{
              type:Object,
              default(){
                return{
                  book:{
                    id:1,
                    name:"新华字典"
                  }
                }
              },
              required: false
            },
            list:{
              type:Array,
              default() {
                return undefined;
              }
            }
          }
        }
        
子组件传父组件

子组件有时候也需要向父组件传参,这时候我们可以通过事件监听达到目的

举例子

<template>
  <div>
    <p>{{msg}}</p>
    //设置提交的按钮
    <button @click="sendParent">提交数据给父组件</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data(){
    return{
      message:'HelloWorld'
    }
  },
  props: {
    msg: {
      type: String,
      default: 'Hello',
      required:true
    },
  },
  methods:{
    //使用this.$emit来进行数据传参
    sendParent(){
      //this.$emit('事件的名称','发送的事件参数')
      this.$emit('inject',this.message);
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

父组件通过监听事件的发生来获取数据

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <!--拿到子组件的数据,通过自定义的事件-->
  <!--2.在父组件,通过v-on监听子组件中自定义的事件-->
  <HelloWorld :msg="message" @inject="getChildMsg"/>
  <p>{{Hello}}</p>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  data(){
    return{
      message:"Hello World!",
      Hello:'',
    }
  },
  methods:{
    //这里对获取的数据进行处理  
    getChildMsg:function (value){
      console.log(value)
      this.Hello = value;
    }
  },
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

3.插槽的使用

这是组件的一种使用,先来定义一个组件

<template>
  <div>
    <h2>我是显示的内容</h2>
    <div>       
        <slot></slot>
    </div>
    </div>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Content",

}
</script>

<style scoped>

</style>

这里的<slot></slot>是插槽的出口,也就是我们需要填的坑,再来看看在父组件中怎么填

<Content><button>按钮</button></Content>
<Content><input placeholder="nihao"></Content>
  <!--如果有多个值,将会一起作为替换元素-->
<Content>><button>按钮</button><input placeholder="nihao"></Content>

然后有一个组件中有多个插槽的这种情况,我们的解决方案是具名插槽,简单来说,就是加个名字

<template>
  <div>
    <h2>我是显示的内容</h2>
    <div>
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Content",

}
</script>

<style scoped>

</style>

父组件中的使用

  <Content>
    <template v-slot:header>
      <h2>我是标题</h2>
    </template>
    <template v-slot:default>
      <div>我是内容</div>
    </template>
    <template v-slot:footer>
      <div>末尾</div>
    </template>
  </Content>

还有缩写形式

<BaseLayout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <template #default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容。所以上面也可以写成:

<BaseLayout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <!-- 隐式的默认插槽 -->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

不过要注意的是:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的

在父组件中进行的数据操作,影响不到子组件,也就是作用域不同。

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐