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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1d43f75f092a4050a8ce31e2d85f6868.gif

🥳博       主初映CY的前说(前端领域)

🌞个人信条想要变成得到中间还有做到

🤘本文核心组件基础概念与全局|局部组件的写法、组件之间传值父传子、子传父


目录

一、组件基础

1.组件初印象

2.组件组成

3.组件的分类与使用

全局|局部组件案例

【额外补充】

二、组件传值

1.父传子

2.子传父

父子组件案例


一、组件基础

1.组件初印象

1.概念

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

2.本质

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

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

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

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

<Root>

<Header></Header>

<Main><Article></Article><Article></Article></Main>

<Aside><Item></Item><Item></Item><Item></Item></Aside>

</Root>

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

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

2.组件组成

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

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

  • <template></template>标签,这里写组件的html结构
  • <script></script>标签这里写组件的js代码
  • <style></style>标签这里写组件的css代码

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

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

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

组件 = (页面)盒子 = (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中的文件。

2.全局组件

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

1.组件分类

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

1.局部组件

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

main.js(核心代码如下

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

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

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

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


【额外补充】

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

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

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

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

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

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

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

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

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

同类名

同css样式

 我们在浏览器中查看效果

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

可见当我们在子组件中加载了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>

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


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

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

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

各位兄弟姐妹们感谢你看到了这里如果代码注释有不清晰的地方欢迎大家留言我会解答喔

下篇文章将讲解【组件进阶与插槽】的用法本专栏将持续更新~~~~~~

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue

“【vue2】组件基础与组件传值(父子组件传值)” 的相关文章