2024.10月18日- Vue2组件开发(3)

news/2024/10/22 8:11:13/

Vue组件开发

一、 ref属性

如果在vue里,想要获取DOM对象,并且不想使用JS的原生语法,那么就可以使用ref属性。ref属性的用法:

1)在HTML元素的开始标记中,或者在Vue子组件中的开始标记中定义,相当于id的替代者

html元素上: <h1 ref="xxx"></h1> 
Vue组件上:  <School ref="xxx"></School>

2)获取方式: 在html标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象(vc)this.$refs.xxx

src/components/School.vue

<template><div class="hello"><h1>{{ schoolName }}</h1></div>
</template>
​
<script>
export default {name: 'School',data(){return {schoolName: "水利电力学院"}}
}
</script>
​

App.vue

<template><div id="app"><h1 v-text="msg" id="title"  ref="title1"></h1><button ref="btn" @click="showInfo">点我显示信息</button><School ref="sch" id="sch1"/></div>
</template>
​
<script>
import School from './components/School.vue'
export default {name: 'App',components: {School},data(){return {msg:"哈哈哈"}},methods:{showInfo(){//console.log(document.getElementById("title"))console.log(this.$refs.title1)  //真实DOM元素console.log(this.$refs.btn)  //真实DOM元素console.log(this.$refs.sch)  //School组件的实例对象(vc)console.log(document.getElementById("sch1"))}}
}
</script>

二、 scoped 样式

2.1 简介

所有组件的style,都会被汇总到一起,如果style中设置的样式名有重复的,那么可能就会后引入的组件的样式会覆盖掉先引入组件的样式。

此时,我们可以在组件的style开始标记里,使用scoped属性,来设置style样式只针对当前组件生效,即局部生效。

注意:App.vue不适合使用scoped属性。

2.2 案例演示

School.vue

<template><div class="demo"><h1>学校信息</h1><h3>学校名称: {{ name }}</h3><h3>学校地址:{{ address }}</h3></div>
</template>
<script>export default {name:"School",data(){return {name:"水利电力",address:"长春净月"}}}
</script>
<!-- scoped  是组件中的样式属性,设置后,只针对于当前组件的样式生效 -->
<style scoped>.demo{background-color:rgb(0, 174, 255);}
</style>

Student.vue

<template><div class="demo"><h1>学生信息</h1><h3>学生名称: {{ name }}</h3><h3>学生年龄:{{ age }}</h3></div>
</template>
​
<script>export default {name:"Student",data(){return {name:"张三",age:18}}}
</script>
​
<style scoped>.demo{background-color: rgb(38, 136, 123);}
</style>

App.vue

<template><div class="demo"><h1>正在学习Vue</h1><School></School><hr><Student></Student></div>
</template>
​
<script>import Student from "./components/Student.vue"import School from "./components/School.vue"export default{name:"App",components:{School,Student},}
</script>
​
<!-- App.vue中写样式,目的是为了其所包含的内容都是该样式,因此不适合使用scoped -->
<style>h1{color:red}
</style>

三、 组件通信属性

3.1 什么是组件通信

组件的数据是独立的,无法直接访问其他组件的数据;想使用其他组件的数据,就需要组件通信。组件通信,就是指组件与组件之间的数据传递

3.2 通信解决方案

3.3 父子通信流程

  1. 父组件通过 props 将数据传递给子组件

  2. 子组件利用 $emit 通知父组件修改更新

 

3.4 父>子通信代码演示

父向子传值步骤

第一步:在父组件中,编写子组件标签时,添加属性和属性值,也就是键值对的形式设置属性和具体值。(发起通信)

<Student  name="李四" gender="女" :age="18"/>         :是v-bind的简写,表示18是表达式

第二步:子组件内部通过props配置项,来接收。(收到通信)

三种配置方式:
-1).简单声明接受信息:  props: ['name','gender','age']
-2).接受的同时限定类型:props:{name:String,gender:String,age:Number}
-3). 限定类型,必要性,默认值等props:{name:{type:String, //约束类型required:true //约束必要性},gender:{type:String,default:"女"  //约束默认值},age:{type:Number,default:100}}

第三步:子组件模板中可以直接使用props接收的值

案例演示:

父组件App.vue

<template><div id="app"><Student  name="李四" gender="女" :age="18" x="1"/><hr><Student  name="王五"/></div>
</template>
​
<script>
import Student from './components/Student.vue'
​
export default {name: 'App',components: {Student},data(){return {msg:"哈哈哈"}},
}
</script>

子组件Student.vue

<template><div><h1>{{msg}}</h1><h2>学生姓名:{{ name }}</h2><h2>学生性别:{{ gender }}</h2><!-- <h2>学生年龄:{{ age+1 }}</h2> --><h2>学生年龄:{{ myAge+1 }}</h2><button @click="add">点我年龄+1</button></div>
</template>
​
<script>
export default {name: 'Student',data(){console.log(this)return {msg:"水利电力学院的学生",// age:18,      props优先级myAge:this.age}},methods:{add(){this.myAge++}},// 简单声明接受// props:["name","gender","age"]// 接收的同时对数据进行类型限制/* props:{name:String,gender:String,age:Number} */
​props:{name:{type:String, //约束类型required:true //约束必要性},gender:{type:String,default:"女"  //约束默认值},age:{type:Number,default:100}}
​
}
</script>

注意:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据

1.default和required一般不同时写(因为当时必填项时,肯定是有值的)

2.default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值

3.5 练习:

将父组件中的各种类型数据,传递给子组件。 只需要使用指令语法书写表达式即可。这种方式就可以自动推断数据类型了。  

 

3.6 子>父通信方式1

第一种方式: 通过父组件给子组件传递函数类型的props实现子给父传递数据。

App.vue

<template><div id="demo"><h1> 老师名字:{{teacherName}}</h1><h1> 学生名字:{{studentName}}</h1><!-- 编写子组件标签时,定义属性,传入函数名 --><Teacher :getTeacherData="getTeacherName"></Teacher><Student :getStudentData="getStudentName"/></div>
</template>
​
<script>
import Teacher from './components/Teacher.vue'
import Student from './components/Student.vue'
​
export default {name: 'App',components: {Teacher,Student},data:function(){return {teacherName:'',studentName:''}},methods:{// 定义函数getTeacherName:function(value){console.log("收到了Teacher组件传过来的名字:"+value);this.teacherName = value;},getStudentName(value){console.log("收到了Student组件传过来的名字:"+value);this.studentName = value;}
​}
}
</script>
<style scoped>#demo{background-color:blueviolet;border: 1px solid blueviolet;}
</style>

Teacher.vue

<template>
    <div>
        序号:<input type="text" :value="id"> <br>
        姓名:<input type="text" v-model="name"> <br>
        年龄:<input type="text" :value="age"> <br>
        性别:<input type="text" :value="gender"> <br>
       <!-- 绑定点击事件,设置回调函数为传过来的函数 -->
        <button @click="sendTeacherName">点我给父组件传值</button>
    </div>
</template>

<script>
export default {
    name:"Teacher",
    data(){
        return {
            id:1,
            name:"王老师",
            age:21,
            gender:'男'
        }
    },
   // 使用props来接受传入的属性-->函数
    props:['getTeacherData'],
    methods:{
        sendTeacherName(){
           //调用传过来的函数,将名字作为参数传入
            this.getTeacherData(this.name);
        }
    }
}
</script>

<style scoped>
    div{
        background-color: pink;
        margin: 20px;
    }
</style>

Student.vue

<template>
<div>序号:<input type="text" :value="id"> <br>姓名:<input type="text" :value="name"> <br>年龄:<input type="text" :value="age"> <br>性别:<input type="text" :value="gender"> <br><button @click="sendStudentName">点我给父组件传值</button></div>
</template>
​
<script>export default {name:"Student",data(){return {id:1001,name:"韩梅梅",age:21,gender:'女'}},props:['getStudentData'],methods:{sendStudentName(){//调用传过来的函数,将名字作为参数传入this.getStudentData(this.name);}}}
</script>
​
<style scoped>div{background-color: skyblue;margin:20px;}
</style>

四、 自定义事件

4.1 简介

除了js中的内置事件,Vue还允许开发者自定义事件。在Vue实例上有以下四个方法,来完成自定义事件的各种操作:

  • vm.$on: 自定义事件监听的核心方法。它允许开发者在Vue实例上注册监听器,以响应特定的事件。

    -1).监听器注册:通过vm.$on(eventName, callback)的形式,将callback函数注册为eventName事件的监听器。当事件被触发时,callback将被调用。
    ​
    -2).执行顺序:事件触发时,所有注册的回调函数将按照它们注册的顺序依次执行。
  • vm.$emit: 自定义事件派发的核心方法。它允许开发者触发自定义事件,从而实现组件之间的通信。

    -1). 事件触发:通过vm.$emit(eventName)的形式,可以触发一个名为eventName的事件。
    -2). 参数传递:使用vm.$emit(eventName, arg1, arg2, ...)触发事件时,可以传递多个参数。这些参数将按顺序传递给监听器的回调函数。 

    ==vm.$emit在Vue组件系统中扮演着至关重要的角色,尤其是在子>父组件的通信中==

    -1).子组件触发:子组件通过调用vm.$emit来触发一个事件,该事件可以被父组件监听。
    -2).父组件监听:父组件通过在子组件的引用上使用v-on指令来监听子组件触发的事件。
  • vm.$off :移除自定义事件监听器的方法,它提供了一种机制来清理不再需要的事件监听,从而避免潜在的内存泄漏问题。

    -1) 移除机制:vm.$off([event, callback]),如果提供了事件名称和回调函数,则只移除特定的监听器;
    -2).如果没有提供参数,则移除所有事件的所有监听器。:   vm.$off()
    -3).灵活性:vm.$off的灵活性体现在可以根据实际情况选择移除单个监听器或全部监听器,以满足不同的开发需求。

    应用场景:

    -1).组件销毁:在Vue组件被销毁前,使用vm.$off移除所有注册的事件监听器,确保组件不会在销毁后继续触发事件,导致不可预期的行为。
    -2).条件性监听:在某些情况下,事件监听可能只在特定条件下需要,一旦条件不再满足,就应该使用vm.$off移除监听器,以避免不必要的资源占用。
  • vm.$once :提供了一种机制,允许事件只被监听一次,在事件触发后自动移除监听器。

    -1).场景应用:适用于那些只需要执行一次的事件处理,例如初始化操作或一次性资源的加载。
    -2).资源管理:通过确保监听器只触发一次,vm.$once有助于避免不必要的资源消耗和潜在的内存泄漏。

4.2 子>父通信方法2:v-on绑定自定义事件

绑定原理:

在编写的子组件标签上使用v-on或者@绑定自定义事件,实际上是将事件绑定到子组件实例对象的VueComponent上。当有人触发了子组件上的这个事件,就会回调绑定到该事件上的函数。

App.vue

<template><div id="demo"><h1> 老师名字:{{teacherName}}</h1><h1> 学生名字:{{studentName}}</h1><!-- 第二种方式:使用v-on|@方式自定义事件。 --><Teacher @getTeacherData="getTeacherName"/><Student @getStudentData="getStudentName"/></div>
</template>
​
<script>
import Teacher from './components/Teacher.vue'
import Student from './components/Student.vue'
​
export default {name: 'App',components: {Teacher,Student},data:function(){return {teacherName:'',studentName:''}},methods:{// 定义函数getTeacherName:function(value){console.log("收到了Teacher组件传过来的名字:"+value);this.teacherName = value;console.log(this);},getStudentName(value){console.log("收到了Student组件传过来的名字:"+value);this.studentName = value;}
​}
}
</script>
<style scoped>#demo{background: linear-gradient(to bottom right ,#2980b9,#ffffff);border: 1px solid #cefff1;}
</style>

Teacher.vue

<template><div>姓名:<input type="text" v-model="name"> <br>年龄:<input type="text" :value="age"> <br><button @click="sendTeacherName">点我给父组件传值</button></div>
</template>
​
<script>
export default {name:"Teacher",data(){return {name:"王老师",age:21,}},methods:{sendTeacherName(){//当有人点击了子组件上的按钮时,会执行sendTeacherName函数,我们在这个函数的逻辑体中,//使用$emit方法来触发该组件实例对象VueComponent上绑定的事件,并且可以传入其他参数//将参数传入回调函数中。this.$emit('getTeacherData',this.name)}}
}
</script>
​
<style scoped>div{background-color: #a6acec;margin: 20px;}
</style>

Student.vue

<template>
<div>
   姓名:<input type="text" :value="name"> <br>
   年龄:<input type="text" :value="age"> <br>
   <button @click="sendStudentName">点我给父组件传值</button>
   </div>
</template>

<script>
   export default {
      name:"Student",
      data(){
         return {
            name:"韩梅梅",
            age:21,
         }
      },
      methods:{
         sendStudentName(){
            //当有人点击了子组件上的按钮时,会执行sendTeacherName函数,我们在这个函数的逻辑体中,
            //使用$emit方法来触发该组件实例对象VueComponent上绑定的事件,并且可以传入其他参数
            //将参数传入回调函数中。
            this.$emit('getStudentData',this.name)
         }
      }
   }
</script>
<style scoped>
   div{
      background-color:#ace7ef;
      margin:20px;
   }
</style>

4.3 子>父通信方法3:$on绑定自定义事件

App.vue

<template><div id="demo"><h1> 老师名字:{{teacherName}}</h1><h1> 学生名字:{{studentName}}</h1><!-- 第三种方式:使用ref和$on方式来自定义事件,更加灵活。 --><Teacher ref="teacher"/><Student ref="student"/></div>
</template>
​
<script>
import Teacher from './components/Teacher.vue'
import Student from './components/Student.vue'
​
export default {name: 'App',components: {Teacher,Student},data:function(){return {teacherName:'',studentName:''}},methods:{// 定义函数getTeacherName:function(value){console.log("收到了Teacher组件传过来的名字:"+value);this.teacherName = value;console.log(this);},getStudentName(value){console.log("收到了Student组件传过来的名字:"+value);this.studentName = value;}},mounted(){// 通过$refs属性获取组件实例对象,然后使用$on来绑定事件,这样的方式更加灵活this.$refs.teacher.$on('getTeacherData',this.getTeacherName)this.$refs.student.$on('getStudentData',this.getStudentName)}
}
</script>
<style scoped>#demo{background: linear-gradient(to bottom right ,#2980b9,#ffffff);border: 1px solid #cefff1;}
</style>

4.4 总结:组件的自定义事件

1)一种组件间通信的方式,适用于:子组件 ====> 父组件通信

2)使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调函数在A中)

3)绑定自定义事件:

  • 第一种方式,在父组件中:<Demo @pClick="test"/><Demo v-on:pClick="test"/>

  • 第二种方式,在父组件中: 使用ref和$on

<Demo ref="demo"/>
mounted(){
    this.$refs.demo.$on('pClick',data)

4)若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法

5)触发自定义事件:this.$emit('pClick',数据)

6)解绑自定义事件:this.$off('pClick')

7)组件上也可以绑定原生DOM事件,需要使用native修饰符

 <Demo @click.native=“f1()”>

注意:通过this.$refs.xxx.$on('pClick',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

4.5 全局事件总线:任意组件之间通信

全局事件总线(GlobalEventBus)是一种可以在任意组件间通信的方式,本质上就是一个对象。它必须满足以下条件:

1. 所有的组件对象都必须能看见他  
2. 这个对象必须能够使用$on、$emit和$off方法去绑定、触发和解绑事件

步骤1)安装全局事件总线:

new Vue({...beforeCreate() {Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm},...
})

步骤2)使用事件总线:

  • 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身

export default {methods(){demo(data){...}}...mounted() {this.$bus.$on('xxx',this.demo)}
}
  • 提供数据:B组件想要提供数据,则在B组件中触发$bus身上的自定义事件

this.$bus.$emit('xxx',data)

建议:最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件

main.js

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  beforeCreate() {
     //定义一个全局总线,也就是所有组件都可以访问到的对象
    Vue.prototype.$bus = this
  },
}).$mount('#app')

Student.vue

<template><div>姓名:<input type="text" v-model="name"> <br>年龄:<input type="text" :value="age"> <br><button @click="sendToTeacher" >点我给Teacher组件传值</button></div>
</template>
​
<script>
export default {name:"Teacher",data(){return {name:"韩梅梅",age:21,}},methods:{sendToTeacher(){console.log("给teacher组件发送信息")this.$bus.$emit('getStudentSendData',this.name);},getTeacherSendData(value){console.log("获取Teacher发送过来的信息");this.name = value;}},mounted() {this.$bus.$on('getTeacherSendData',this.getTeacherSendData)},beforeDestroy(){this.$bus.$off('getTeacherSendData')}
}
</script>
​
<style scoped>div{background-color: pink;margin: 20px;}
</style>

Teacher.vue

<template>
    <div>
        姓名:<input type="text" v-model="name"> <br>
        年龄:<input type="text" :value="age"> <br>
        <button @click="sendToStudent" >点我给Student组件传值</button>
    </div>
</template>

<script>
export default {
    name:"Teacher",
    data(){
        return {
            name:"王老师",
            age:21
        }
    },
    methods:{
        sendToStudent(){
            console.log("给Student发送信息");
            this.$bus.$emit('getTeacherSendData',this.name)
        },
        getStudentSendData(value){
            console.log("获取Student发送过来的信息");
            this.name = value;
        }
    },
    mounted() {
        this.$bus.$on('getStudentSendData',this.getStudentSendData)
    },
    beforeDestroy(){
        this.$bus.$off('getStudentSendData')
    }
}
</script>

<style scoped>
    div{
        background-color: skyblue;
        margin: 20px;
    }
</style>

 


http://www.ppmy.cn/news/1541013.html

相关文章

大数据面试题整理——Yarn

系列文章目录 第一章 HDFS面试题 第二章 MapReduce面试题 文章目录 系列文章目录什么是 Yarn&#xff1f;一、Yarn 的主要组件及其功能是什么&#xff1f;二、Yarn 中的容器&#xff08;Container&#xff09;是什么&#xff1f;三、简述 Yarn 的工作流程。四、Yarn 如何进行资…

Python网络请求库requests的10个基本用法

大家好&#xff01;今天我们要聊聊Python中非常实用的一个库——requests。这个库让发送HTTP请求变得超级简单。无论你是想抓取网页数据还是测试API接口&#xff0c;requests都能派上大用场。下面我们就一起来看看如何使用requests完成一些常见的任务。 引言 随着互联网技术的…

高中数学网盘资料(每题有解析和知识点)

一、究极超能学习资源高中版 一数作为播放量过亿的哔站up实力非同一般 链接&#xff1a;https://pan.baidu.com/s/1xrcAlq6wj_LMYHcbxAKAWg 提取码&#xff1a;7MBW 复制这段内容打开「百度网盘APP 即可获取」 二、必刷题高考合订本&#xff08;刷题必备&#xff09; 链接&am…

lazyLoad

//1.通过React的lazy函数配合import()函数动态加载路由组件 > 路由组件代码会被分开打包 const Login lazy(()>import(/pages/Login)) //2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面 <Suspense fallback{<h1&…

支持国密算法的数字证书-国密SSL证书详解

在互联网中&#xff0c;数字证书作为标志通讯各方身份信息的数字认证而存在&#xff0c;常见的数字证书大都采用国际算法&#xff0c;比如RSA算法、ECC算法、SHA2算法等。随着我国加强网络安全技术自主可控的大趋势&#xff0c;也出现了支持国密算法的数字证书-国密SSL证书。那…

【BUG】解决已安装anaconda的pycharm中jupyter服务器中出现的import jieba失败问题

目录 确认已安装anacondaAnaconda权限问题修改权限结束 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。 确认已安装anaconda 如图&#xff0c;已…

人工智能:塑造未来生活与工作的力量

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《热点时事》 期待您的关注 引言 随着人工智能技术的不断发展&#xff0c;我们已经看到了它在各行业带来的巨大变革。 在医疗行业中…

jmeter中用csv data set config做参数化2

在jmeter中&#xff0c;使用csv data set config进行参数化是很重要的一个功能&#xff0c;但是这个功能的使用需要十分仔细和小心&#xff0c;因为细节之处往往决定着结果的正确与否。 举例&#xff1a; 一个登录接口用加密密码登录&#xff0c;一个登录接口用原始密码登录。…