IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue.js组件详解 -> 正文阅读

[JavaScript知识库]vue.js组件详解

一、组件的概念及复用

1.1 为什么要使用组件

组件(component)是vue.js最核心的功能,用来实现局部(特定)功能效果的代码集合(html/css/js/image…..)。

组件是可复用的 Vue 实例, 把一些公共的模块抽取出来,然后写成单独的的工具组件或者页面,在需要的页面中就直接引入即可那么我们可以将其抽出为一个组件进行复用。例如页面头部、侧边、内容区,尾部,上传图片,等多个页面要用到一样的就可以做成组件,提高了代码的复用率

非单文件组件:一个文件中包含多个组件。(真正开发中几乎不用)

单文件组件:一个文件中只包含1个组件。

单文件组件由一个xxx.vue 文件的组成(3 个部分):

1. 模板页面

<template>
页面模板
</template>

2. JS 模块对象

<script>
export default {
data() {return {}}, methods: {}, computed: {}, components: {}
}
</script>

3. 样式

<style>
样式定义
</style>

二、使用props传递数据

2.1 基本用法

组件不仅仅是把模板的内容进行复用,更重要的是组件间的通信,通常父组件的模板中包含子组件,父组件要正向地向子组件传递数据以及参数,子组件接收到参数后再根据参数的不同来渲染不同的内容或执行操作。这个正向传递数据的过程就是通过props来实现的。

父组件:vue-cli创建的项目结构中的App.vue为组件之根(父组件)

通过列表页(父组件)与列表项目组件(子组件)为例子,演示props的使用。

父组件示例代码(App.vue):

<template>
  <div id="app">
    <h1>这是列表页</h1>
    <!-- 3.组件调用,并向子组件传递了参数message -->
    <ListItem message="来自列表页的数据"></ListItem>
  </div>
</template>

<script>
 //1.引入子组件ListItem
import ListItem from '@/components/ListItem'
export default {
  name: 'App',
  data(){
    return{
    }
  },
 //2.注册子组件ListItem
  components:{ListItem}  
}
</script>

<style>
</style>

子组件(列表项目组件)接收父组件传递过来的数据,子组件列表项目代码(ListItem.vue):

<template>
  <div class="list">
      <ul>
          <li>这是第一条数据</li>
      </ul>
      <!-- 在页面中把父组件传递过来的数据显示出来 -->
      <p>{{message}}</p>
      <p>{{msg}}</p>
  </div>
</template>

<script>
export default {
    name:'ListItem',
    data(){
        return{
            msg:'我是组件本身的数据'

        }
    },
    //通过props接收父组件传递过来的数据
    props:["message"]
}
</script>

<style scoped>
.list{
    color:#f00;
}
.list p{
    font-weight: 700;
}
</style>

?props中声明的数据与组件data函数返回的数据的主要区别:

  • props中声明的数据来自父级,而data中是组件自己的数据,作用域是组件本身;
  • 这两种数据都可以在模板(template)及方法(method)中使用;

?使用v-bind指令动态绑定props值:

父组件示例代码(App.vue):

<template>
  <div id="app">
    <h1>这是列表页</h1>
    <!-- 3.组件调用,并向子组件动态传递了参数message -->
    <button @click="change()">改变数据</button>
    <ListItem :message="listdata"></ListItem>
  </div>
</template>

<script>
 //1.引入子组件ListItem
import ListItem from '@/components/ListItem'
export default {
  name: 'App',
  data(){
    return{
      listdata:'原始数据'
    }
  },
  methods:{
    change(){
      this.listdata='单击按钮之后的数据'
    }
  },
 //2.注册子组件ListItem
  components:{ListItem}  
}
</script>

<style>
</style>

子组件(列表项目组件)接收父组件动态传递过来的数据,子组件列表项目代码(ListItem.vue)不变。

?初始状态下,listdata设置的字符串为“原始数据”,如左图,单击改变数据的按钮之后,listdata值改变为“单击按钮之后的数据”,如右图所示。

2.2 单向数据流

上一节我们讲到父组件数据变化可以传递给子组件,但是反过来是不成立的,所以props传递数据是单向的。之所以这么设计,就是尽可能将父子组件解耦,避免子组件无意间修改父组件的状态。

业务中经常会遇到两种需要改变props传递过来数据的情况:

父组件传递初始值,子组件将其初始值保存起来,再自己作用域内可以随意使用和更改,这个时候可以在子组件的data中再声明一个数据来引用父组件传递过来的数据。

父组件代码示例:(App.vue)

<template>
  <div id="app">
    <h1>这是列表页</h1>
    <!-- 3.组件调用,并向子组件动态传递了参数message -->
    <ListItem :message="count"></ListItem>
  </div>
</template>

<script>
 //1.引入子组件ListItem
import ListItem from '@/components/ListItem'
export default {
  name: 'App',
  data(){
    return{
      count:'100'
    }
  },
 //2.注册子组件ListItem
  components:{ListItem}  
}
</script>

<style>
</style>

子组件代码: (ListItem.vue)

<template>
  <div class="list">
      <ul>
          <li>这是第一条数据</li>
      </ul>
      <!-- 在页面中把父组件传递过来的数据显示出来 -->
      <p>{{receive}}</p>
      <p style="color:green">{{msg}}</p>
  </div>
</template>

<script>
export default {
    name:'ListItem',
    data(){
        return{
            msg:'我是组件本身的数据',
            receive:this.message
        }
    },
    //通过props接收父组件传递过来的数据
    props:["message"]
}
</script>

<style scoped>
.list{
    color:#f00;
}
.list p{
    font-weight: 700;
}
</style>

子组件中声明了receive,在组件初始化的时候就会获得来自父组件的message,之后就与message无关了,只需要维护receive,这样就避免了直接操作message。

三、组件通信

通过前面的学习,我们已经知道父组件与子组件通信通过props传递数据就可以,但是vue组件通信的场景远不止这一种,最容易想到的还有子组件传给父组件。组件之间传值可以用下图表示:

?组件通信流程图

3.1 自定义事件及$emit方法

Vue.js允许正向传值,也就是父组件传值给子组件。正向传值不需要条件触发,是主动的,逆向传值则是不允许的,需要主动触发,需要主动抛出自定义事件去监听。

语法:

this.$emit('event',val)

$emit为实例方法,用来触发事件监听。其中,参数event代表自定义事件名称,参数val代表通过自定义事件传递的值,注意这里的val为可选参数。

示例代码:(父组件App.vue)

<template>
  <div id="app">
    <h1>父组件</h1>
    <p>子组件传递的数据:{{message}}</p>
    <!-- 通过父组件给子组件绑定一个自定义事件change,实现子给父传数据 -->
    <ListItem @change='getVal'></ListItem>
  </div>
</template>

<script>
 //1.引入子组件ListItem
import ListItem from '@/components/ListItem'
export default {
  name: 'App',
  data(){
    return{
      message:""
    }
  },
  methods:{
    getVal(val){
      this.message=val
    }
  },
 //2.注册子组件ListItem
  components:{ListItem}  
}
</script>

<style>
</style>

示例代码:(子组件ListItem.vue)

<template>
  <div class="list">
      <h1>子组件</h1>
      <button @click="fn()">单击子组件传值父组件</button>
  </div>
</template>

<script>
export default {
    name:'ListItem',
    data(){
        return{
            cMsg:"子组件要传递给父组件的数据信息"
        }
    },
    methods:{
        fn(){
            this.$emit("change",this.cMsg)
        }
    }
}
</script>
<style scoped>

</style>

?

??? emit初始显示状态???????????????????????????????????????????? 单击按钮之后传值父组

3.2 兄弟组件通信的处理方式

兄弟组件之间的传值最容易想到的解决方案是通过共同的父组件进行中转,这里假设一个场景,组件1中的某个数量需要在组件2中同步展示,这个时候就会涉及到兄弟组件之间的传值。通过一个案例来看一下具体代码的实现方式:

示例代码:(App.vue)

<template>
  <div id="app">
    <h1>父组件</h1>
    <p>{{message}}</p>
    <child-one @change='getVal'></child-one>
    <child-two :count="message"></child-two>
  </div>
</template>

<script>
 //1.引入子组件ListItem
import ChildOne from './components/ChildOne.vue'
import ChildTwo from './components/ChildTwo.vue'
export default {
  name: 'App',
  data(){
    return{
      message:0
    }
  },
  methods:{
    getVal(val){
      this.message=val
    }
  },
 //2.注册子组件ListItem
  components:{ChildOne,ChildTwo}  
}
</script>

<style>
</style>

示例代码:(ChildOne.vue

<template>
  <div class="one">
      <h3>子组件</h3>
      <button @click="fn">传值到父组件</button>
  </div>
</template>

<script>
export default {
    name:'ChildOne',
    data(){
        return{
            num:'10'
        }
    },
    methods:{
        fn(){
            this.$emit('change',this.num);
        }
    }

}
</script>

<style>
.one{
    border: 1px solid #000;
    padding: 10px;
    margin-bottom: 10px;

}
</style>

示例代码:(ChildTwo.vue

<template>
  <div class="two">
      <h3>子组件2</h3>
      <P>{{count}}</P>
  </div>
</template>
<script>
export default {
    name:'ChildTwo',
    data(){
        return{

        }
    },
    props:["count"]
}
</script>
<style>
.two{
    border: 1px solid #000;
    padding: 10px;
    margin-bottom: 10px;
}
</style>

兄弟组件传值初始显示

?兄弟组件传值之后显示

四、slot分发内容

4.1 什么是slot

slot的官方定义是用于组件内容分发,slot还有一个形象的名字“插槽”。简单通俗的解释就是在组件化开发中,虽然组件是一样的,但是在不同的使用场景,组件的某一部分需要有不同的内容显示。

4.2 匿名slot

匿名slot从字面理解就是没有名字的插槽,特点是可以放任何内容。

假设场景:设想一个弹出提示框的场景,提示框都包括头部、中间内容和底部内容三部分,头部和底部都是固定不变的,改变的知识中间内容,所以我们在定义组件时可以将中间内容定义为插槽

示例代码:(子组件popup.vue)

<template>
  <div>
      <p>头部区域</p>
      <!-- 在变化内容区域定义一个插槽 -->
      <slot>如果没有分发内容,则显示默认提示</slot>
      <p>底部区域</p>
  </div>
</template>

<script>
export default {
    data(){
        return{

        }
    }

}
</script>
<style>
</style>

示例代码:(父组件App.vue)

<template>
  <div id="app">
    <popup>
      <!-- 插槽显示的具体内容 -->
      <h1>显示弹出框内容</h1>
    </popup>
  </div>
</template>

<script>
 //1.引入子组件popup
import Popup from './components/popup.vue'
export default {
  name: 'App',
  data(){
    return{
      message:0
    }
  },
  methods:{
  
  },
 //2.注册子组件ListItem
  components:{Popup}  
}
</script>

<style>
</style>

?4.3 具名slot

具名slot可以用一个特殊属性name来配置如何分发内容,多个slot可以有不同的名字,具名slot将匹配内容片段中有对应slot特性的元素。

代码示例:(computer.vue子组件)

<template>
  <div>
      <slot name="CPU">这儿是CPU插槽</slot>
      <slot name="GPU">这儿是显卡插槽</slot>
      <slot name="Memory">这儿是内存插槽</slot>
      <slot name="Hard-drive">这儿是硬盘插槽</slot>
  </div>
</template>

<script>
export default {
  data(){
    return{

    }
  },
  components:{}

}
</script>
<style>
</style>

?代码示例:(App.vue父组件)

<template>
  <div id="app">
    <computer>
      <!-- 插槽显示的具体内容 -->
      <div slot="CPU">Initel Core i7</div>
      <div slot="GPU">GTX980Ti</div>
      <div slot="Memory">Kingston 32G</div>
      <div slot="Hard-drive">Samsung SSD 1T</div>
    </computer>
  </div>
</template>

<script>
 //1.引入子组件computer
import Computer from './components/computer.vue'
export default {
  name: 'App',
  data(){
    return{
      message:0
    }
  },
  methods:{
    
  },
 //2.注册子组件computer
  components:{Computer}  
}
</script>

<style>
</style>

?

?

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:20:01  更:2022-03-08 22:23:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:21:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码