【vue2】组件基础与组件传值(父子组件传值)

简介: 组件基础概念与全局|局部组件的写法、组件之间传值(父传子、子传父)

一、组件基础

1.组件初印象

1.概念:

组件是把页面上可重用的部分封装成组件,方便项目的开发的维护

2.本质:

组件是有HTML结构,css样式,js业务逻辑的HTML自定义标签(下面详解)

上述这个描述可能存在一点点抽象,vue组件这个描述与我们之前学过的div用大盒子装载是一个意思的。我们拿官网的图来给兄弟姐妹们讲解:

385fece196f34d458e80cca81510f0e7.png

上述我们之前一般是用三个大的div(Header、Main、Aside)来封装我们的页面的再细分下去其他模块结构,现在我们用vue组件表示来就是再Root这个根组件中用引入对应的组件标签就可以了

比如上述结构可以用标签这样写:

记住组件的本质:组件是有HTML结构,css样式,js业务逻辑的HTML自定义标签

这样是不是对组件有点感觉了呢!那我们来看看我们的组件是怎么组成的

2.组件组成

一个组件(.vue文件)由三个标签组成:

小提示 : 快速生成组件三大部分的快捷键:

  • 标签,这里写组件的html结构
  • 标签,这里写组件的js代码
  • 标签,这里写组件的css代码

接下来我们来看个实际的例子

(小提示:按下<可快速生成一个.vue后缀的结构)

338cfb5f172c4a67af4c5d74d5b5775d.png

下面这张图兄弟姐妹们仔细看,对我们学vue很重要呦

764be09206a242d9ad0c9562fd2eb6a1.png

组件 = (页面)盒子 = (html)自定义标签(HTML+CSS+JS) = (代码).vue文件 = (内存)vue实例

3.组件的分类与使用

我们的组件分为两种:①局部组件 ②全局组件

1.局部组件

就是在当前的.vue后缀文件中生效,出了当前.vue后缀的文件就失效。

下面我们来看看我们怎么使用我们的组件:

三大步:①导入 ②注册 ③使用

1.导入局部组件 : 在scrip标签中导入
      import 组件名 from '组件路径'
2.挂载组件 : 在export default里面写一个属性components
      export default {
        components: {
          "标签名": 组件名
        }
      }
3.使用组件 : 像标签一样使用即可,组件可以理解为一个自定义标签
<组件名></组件名>

全局|局部组件案例:

下面我创建两个.vue文件

1.App.vue

<template>
  <!-- 1.组件html代码,组件默认会把template里面的根元素作为挂载点因此下面不需要写el -->
  <!-- 为什么组件data必须是一个函数 :因为组件是需要复用的,如果组件data是一个对象,那么组件在复用的时候就会使用相同的对象地址。一旦在一个地方被修改,其他的也会跟着修改。
        如果组件data是一个函数,组件在每一次复用的时候就会调用这个函数得到一个全新的对象,这样就可以做到在复用的时候每个组件之间的数据都是独立的,互不影响。 -->
  <div>
    <h1>我是App.vue</h1>
    <!-- 1.组件的使用 -->
    <MyPens></MyPens>
  </div>
</template>
<script>
// 1.组件业务js导入
import MyPens from '@/components/MyPens.vue'
export default {
  // 2.组件的注册
  components: {MyPens},
  // 存放vue的实例对象
  data() {
    return {
      // 在这里写data数据.必须是函数!!!,{}本质是new出来了一个
    }
  },
  methods: {},
  computed: {},
}
</script>
<style>
/* 3.组件的样式 */
</style>

2.MyPens.vue

<template>
<div> 
存放HTML结构,不写标签就会报错
<hr>
{{ msg }}
</div>
<!-- 
  1.组件中的最外层父元素只能有一个,不能添加两个平级父元素
  正确:  <div> <div></div> <div>
  错误:   <div></div> <div></div> -->
</template>
<script>
// 2.js代码,写组件js业务逻辑
export default {
    //之前vue实例的代码写在这里:可以放data,methods,计算属性、侦听器等
    //注意哟,组件里面的data是一个函数,返回值就是之前vue实例中的data对象
    data(){
        return{
            msg:'我是初映CY,我是放在MyPens中的'
        }
    },
}
</script>
<style>
/* 3.css:写组件样式 */
</style>

上述我们写了两个.vue分别为App.vue与MyPens.vue,我们在App.vue中引入我们MyPens.vue中的文件。

d1b22b1e4a034cdead18587fd62cf723.png

2.全局组件

使用方法与局部组件一样,唯一区别就是该组件的注册是在main

1.组件分类:

1.局部组件    2.全局组件

1.局部组件:

注册方法与局部组件注册一致,但是注册不在需要的.vue文件中注册,而是在main.js文件中注册

main.js(核心代码如下)

import MyButton from "@/components/MyButton.vue"//文件路径
Vue.component('MyButton',MyButton)//注册全局

a60b57ef5c1e4b4e81d985585987674e.png

下面我们引入下我们的组件到别的文件中

a1a3025de2284d298f1fccb6858e26fa.png

我们引入了到App与MyPens文件中,我们打开App.vue

16df197035cf457eb087baf2f8297f42.png

可以看到我们的全局组件引入成功啦,以上就是全局与局部组件的使用方法。

【额外补充】

①浏览器默认打开加载App.vue文件

问题引入:为什么我们浏览器打开的默认是App.vue的文件呢?其实是因为我们在main.js中确定了App.vue是跟根文件入口,我们项目打开默认走的就是App.vue

这是我们的main.js文件现在的情况:

b6b4826728fa4b1e9ff4fe5a8601a565.png

当我们修改了框起来的配置之后的样子:

411179bd7f2e462fba69711127bb84fb.png

当我们按照这个配置重新运行的时候页面加载的是:(在终端使用命令npm run serve)

b3c45ea164a7487d806f67d7b5239f62.png

可以发现我们成功的将页面的默认加载文件给更改了,改成了MyPens.vue。

②提高子组件css样式的权重

问题引入:当我们的子组件与父(根组件)有重名的的时候,我们是优先加载哪一个的css样式呢?

当我们MyPens.vue与App.vue都有个大div类名为color,并且我们都设置了相同的css样式:

同类名:

f0952ae8e87d4457a823027475195a06.png

同css样式:

0636f59f2f5e47a6aab6a64ef9fb6e31.png

我们在浏览器中查看效果:

35b8e58c9f76440282d7cafef8e97671.png

发现了我们子与父发生了同名的css样式,我们优先加载的是父(根)组件的。但是我们需要子属性的咋办?使用scoped属性即可

183759792eb5444abe4b086da546b188.png

可见当我们在子组件中加载了scoped属性之后,我们子组件的样式就不会被覆盖掉,而是子显示子组件的样式,父显示父组件的样式。

二、组件传值

1.父传子

父传:

父中用v-bind来传数据

如:(v-bind:"属性名" =属性值      该指令可简写为:属性名="属性值")

<子组件> 
:arr="list"//这两种写法均可,推荐使用这种
 v-bind:id="item.id"
 <子组件> 

子收:

子组件中声明props来接收

props写的有两种:

①不声明数据类型写法(不推荐使用)

props:["属性名","属性名"]

如:

props:["name","price","id"]

注意点:是用数组包裹属性名

②声明数据类型写法(推荐使用)

对象名: {
      type: 数据类型, //注意前面需要加:解析不然是字符串类型
      default: xxx, //默认值,可以不用写默认值
    },

如:

props: {
    price: {
      type: Number, //注意前面需要加:解析不然是字符串类型
      default: 100, //默认值
        }
    }

2.子传父

子传:

this.$emit('方法名', 传递的数据)

如:

this.$emit('price', this.id)

注意点:方法名的书写需要引号

父收:

<子组件>
        @子组件定义的方法名='新方法名'
</子组件>

如:

我们在父组件中导入组件并且讲方法名命名为dochange

    <myGoods
      @price="doChange"
    ></myGoods>

在methods:{}中重新定义我们的方法dochange(此处是子组件传递过来的数据),这样我们父子传值就完成了。

methods: {
    // 接收MyGoods传来的值 3.根据定义事件来写属于我们的方法
    doChange(id) {
      //看子文件中传入的事件对象
      console.log(id)
      this.list.forEach((element) => {
        if (element.id === id) {
          element.price--
        }
      })
    },
  },

父子组件案例:

子组件MyGoods.vue

<template>
  <div class="box">
    <!-- 2.获取data中的值 -->
    <p>商品名称:{{ name }}</p>
    <p>商品价格:{{ price }}</p>
    <p>商品编号:{{ id }}</p>
    <button @click="doClick">点我来一🔪</button>
  </div>
</template>
<script>
export default {
  // 1.父传子(单项数据流):子组件中声明props,会平铺到数据中
  // props:["name","price","id"]
  // 上述写法不可传指定类型值,因此我们优化下写法:
  props: {
    name: String,
    price: {
      type: Number, //注意前面需要加:解析不然是字符串类型
      default: 100, //默认值
    },
    id: {
      type: [String, Number],
      required: true, //必传
    },
  },
  methods: {
    // 2.&emit:子传父 自定义事件
    doClick() {
      // price是我们自定义的方法,this.id是传入的实参
      this.$emit('price', this.id)
      // this.price-- //子组件与父组件绑定了,当只在子组件修改的时候,与父组件不同步因此会报错。一般处理数据都是子传父
      // console.log(this.price);
    },
  },
}
</script>
<style scoped>
div {
  border: 2px solid rgb(6, 58, 199);
}
</style>

父组件MyGoods.vue

<template>
  <div>
    <h1>我是父组件</h1>
    <!-- 3.使用组件 -->
    <myGoods
      v-for="item in list"
      :key="item.id"
      :name="item.name"
      :price="item.price"
      :id="item.id"
      @price="doChange"
    ></myGoods>
  </div>
</template>
<script>
// 1.导入组件
import MyGoods from '@/components/MyGoods.vue'
export default {
  components: { MyGoods },
  //2. 注册事件
  data() {
    return {
      list: [
        {
          name: '苹果手机',
          price: 8888,
          id: 1,
        },
        {
          name: '小米手机',
          price: 5888,
          id: 2,
        },
        {
          name: '华为手机',
          price: 7888,
          id: 3,
        },
      ],
    }
  },
  methods: {
    // 接收MyGoods传来的值 3.根据定义事件来写属于我们的方法
    doChange(id) {
      //看子文件中传入的事件对象
      console.log(id)
      this.list.forEach((element) => {
        if (element.id === id) {
          element.price--
        }
      })
    },
  },
}
</script>
<style>
div {
  border: 2px solid rgb(234, 226, 12);
}
</style>

好了兄弟姐妹们,先看下实际的效果:


9f2d2262e9bd45c897bd2ec9fcd7282c.gif


可以看到我们的传值是完全OK的,父组件App.vue里面的数据与我们子文件MyGoods里面的数据是一摸一样的。可得知这两者数据相同并且得到了修改。

下面我们来尝试下,我们父传子之后,我们子不传递给父的情况:

f3f3b3cf42454cf39197d6c137a91875.png

这张图就灵活的显示了当我们在子组件中不传递数据给我们的父组件时,我们只是在我们的页面修改数据,这样就出现了一个小小的BUG,我们页面显示的(子组件数据)与我们App.vue中的数据并不是同步更新的,且当我们点击 来一刀 的时候右上交也会有报错提示。所以可以得出一个结论:当我们需要修改父中的数据我们需要传递过去给父改,我们的props是单项传输之读取的,需要$emit()传过去。



相关文章
|
15天前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
134 2
|
4月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
571 0
|
6月前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
770 4
|
4月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
4月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件的实现代码:支持自定义表情库、快捷键发送和输入框联动的聊天表情解决方案
本文详细介绍了在 Vue 项目中实现一个功能完善、交互友好的表情包输入组件的方法,并提供了具体的应用实例。组件设计包含表情分类展示、响应式布局、与输入框的交互及样式定制等功能。通过核心技术实现,如将表情插入输入框光标位置和点击外部关闭选择器,确保用户体验流畅。同时探讨了性能优化策略,如懒加载和虚拟滚动,以及扩展性方案,如自定义主题和国际化支持。最终,展示了如何在聊天界面中集成该组件,为用户提供丰富的表情输入体验。
326 8
|
4月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件实现代码及详细开发流程解析
这是一篇关于 Vue 表情包输入组件的使用方法与封装指南的文章。通过安装依赖、全局注册和局部使用,可以快速集成表情包功能到 Vue 项目中。文章还详细介绍了组件的封装实现、高级配置(如自定义表情列表、主题定制、动画效果和懒加载)以及完整集成示例。开发者可根据需求扩展功能,例如 GIF 搜索或自定义表情上传,提升用户体验。资源链接提供进一步学习材料。
213 1
|
4月前
|
JavaScript 前端开发 UED
Vue 项目中如何自定义实用的进度条组件
本文介绍了如何使用Vue.js创建一个灵活多样的自定义进度条组件。该组件可接受进度段数据数组作为输入,动态渲染进度段,支持动画效果和内容展示。当进度超出总长时,超出部分将以红色填充。文章详细描述了组件的设计目标、实现步骤(包括props定义、宽度计算、模板渲染、动画处理及超出部分的显示),并提供了使用示例。通过此组件,开发者可根据项目需求灵活展示进度情况,优化用户体验。资源地址:[https://pan.quark.cn/s/35324205c62b](https://pan.quark.cn/s/35324205c62b)。
140 0
|
6月前
|
存储 JavaScript 前端开发
基于 ant-design-vue 和 Vue 3 封装的功能强大的表格组件
VTable 是一个基于 ant-design-vue 和 Vue 3 的多功能表格组件,支持列自定义、排序、本地化存储、行选择等功能。它继承了 Ant-Design-Vue Table 的所有特性并加以扩展,提供开箱即用的高性能体验。示例包括基础表格、可选择表格和自定义列渲染等。
417 6
|
11月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
243 64
|
11月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
345 64

热门文章

最新文章