113.【Vue-细刷-04】(二)

简介: 113.【Vue-细刷-04】

(二十五)、自定义事件 (父子组件)

1.A组件想让B组件给自己传递数据,那么就要给B组件绑定自定义事件。

2.自定义回调放在哪里,哪里就能够接收数据。非$emit()是自定义回调函数

1.儿子传递数据给父亲 (原始)

App.vue

<template>
  <div class="app">
    <h2>我是App组件</h2>
    <!-- 2. 父亲传递给儿子 -->
    <Demo :receive_son="receive_one"/>
    <h2>{{username}}</h2>
  </div>
</template>
<script>
import Demo from "./components/Demo.vue";
export default {
  name: "App",
  components: {
    Demo,
  },
  data() {
    return {
        username:'111'
    }
  },
  // TODO: 1.父亲创建一个接受儿子传递过来的方法
  methods: {
    receive_one(data_one){
        this.username=data_one;
    }
  }
};
</script>
<style>
.app{
    background-color: brown;
    padding: 10px;
}
</style>

Demo.vue 儿子

<template>
  <div class="demo">
    <h2 >我是Demo2组件</h2>
    <button @click="send_data">点我向父类传送数据</button>
  </div>
</template>
<script>
export default {
  name: "Demo",
  data() {
    return {
        name:'ckqn'
    }
  },
//  TODO: 1.儿子接受数据
    props:['receive_son'],
// TODO: 2.儿子创建方法传递给父亲
    methods:{
        send_data(){
            this.receive_son(this.name)
        }
    }
};
</script>
<style>
    .demo{
        background-color: antiquewhite;
    }
</style>

2.儿子传递数据给父亲 (自定义事件 $emit) ⭐

  • (适用于父子组件、不适用兄弟组件):

一般自定义事件都会放在组件上

1.给子组件自定义事件:自定义事件会放在子组件的vc上
<Demo @jsxs="test"/>
methods: {
    test(data_one){
        this.username = data_one
    }
  },

App.vue

<template>
  <div class="app">
    <h2>我是App组件</h2>
    <!-- 
        如下代码是给Demo的组件实列对象定义一个jsxs事件,只要Demo组件实列对象触发了jsxs事件,那么就调用test函数
        组件->一般添加的是自定义事件
     -->
    <Demo @jsxs="test"/>
    <h2>{{username}}</h2>
  </div>
</template>
<script>
import Demo from "./components/Demo.vue";
export default {
  name: "App",
  components: {
    Demo,
  },
  data() {
    return {
        username:'111'
    }
  },
  methods: {
    test(data_one){
        this.username = data_one
    }
  },
};
</script>
<style>
.app{
    background-color: brown;
    padding: 10px;
}
</style>

Demo.vue

2.子组件通过$emit向父亲传递数据 : 第一个参数是自定义事件名,后面的是参数无限制
    methods:{
        send_data(){
        // 当jsxs这个自定义的事件被触发的时候会像父App.vue传递一个数据
            this.$emit('jsxs',this.name) //把子类的参数传递给父类
        }
    }
<template>
  <div class="demo">
    <h2 >我是Demo2组件</h2>
    <button @click="send_data">点我</button>
  </div>
</template>
<script>
export default {
  name: "Demo",
  data() {
    return {
        name:'ckqn'
    }
  },
    methods:{
        send_data(){
            this.$emit('jsxs',this.name) //把子类的参数传递给父类
        }
    }
};
</script>
<style>
    .demo{
        background-color: antiquewhite;
    }
</style>

3.儿子传递数据给父亲 (ref 自定义事件实现)

1.给子组件设置ref。 在组件上设置ref就是获取的组件的实列对象
<Demo ref="demoA"/>
2.利用mounted进行挂载实现自定义
  mounted() {
    this.$refs.demoA.$on('jsxs',this.test)  //第一个参数是自定义自定义事件名和子组件emit对应,第二个是父App.vue绑定的函数
  },

App.vue

<template>
  <div class="app">
    <h2>我是App组件</h2>
    <!-- 
        如下代码是给Demo的组件实列对象定义一个jsxs事件,只要Demo组件实列对象触发了jsxs事件,那么就调用test函数
        组件->一般添加的是自定义事件
     -->
    <Demo ref="demoA"/>
    <h2>{{username}}</h2>
  </div>
</template>
<script>
import Demo from "./components/Demo.vue";
export default {
  name: "App",
  components: {
    Demo,
  },
  data() {
    return {
        username:'111'
    }
  },
  methods: {
    test(data_one){
        this.username = data_one
    }
  },
  mounted() {
    this.$refs.demoA.$on('jsxs',this.test)
  },
};
</script>
<style>
.app{
    background-color: brown;
    padding: 10px;
}
</style>

Demo.vue 不变

<template>
  <div class="demo">
    <h2 >我是Demo2组件</h2>
    <button @click="send_data">点我</button>
  </div>
</template>
<script>
export default {
  name: "Demo",
  data() {
    return {
        name:'ckqn'
    }
  },
    methods:{
        send_data(){
            this.$emit('jsxs',this.name) //把子类的参数传递给父类
        }
    }
};
</script>
<style>
    .demo{
        background-color: antiquewhite;
    }
</style>

4.todoList更换为自定义事件

App.vue

<!-- 1.头部 将父APP.VUE的addFather方法传递给子组件-->
      <Header @addFatherA="addFather"/>
<template>
  <div>
   <div class="todo-container">
    <div class="todo-wrap">
      <!-- 1.头部 将父APP.VUE的addFather方法传递给子组件-->
      <Header @addFatherA="addFather"/>
      <!-- 2.列表 : 将父APP.VUE的todos数组传递给子组件-->
      <list 
      :todosA="todos" 
      :updateFatherA="updateFather"
      :deleteFatherA="deleteFather"
      />
      <!-- 3.底部导航 -->
      <Footer 
      :FooterTodos="todos"
      :updateAllFatherA="updateAllFather"
      :clearAllDoneFatherA="clearAllDoneFather"
      />
    </div>
  </div>
  </div>
</template>
<script>
  // 1.引入组件
  import Header from './components/Header.vue'
  import List from './components/List.vue'
  import Footer from './components/Footer.vue'
export default {
  name:'App', // 目的是在浏览器VUE插件中的名字都是App不会被改变。
  // 2.注册组件
  components:{
    Header,
    List,
    Footer
  },
  data() {
    return {
      todos:[]
    }
  },
  methods: {
    addFather(todoObj){
      // 这个方法是对todos这个数组的尾部追加对象todoObj
      this.todos.unshift(todoObj)
    },
  // 更新
    updateFather(index,doneA){
      this.todos[index].done=doneA
    },
    // 删除
    deleteFather(index){
    // 根据坐标删除数据
    this.todos.splice(index,1)
  },
  // 全选或者不选
  updateAllFather(doneOption){
    // map():创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。
      this.todos=this.todos.map((value)=>{  // 这个参数是遍历的单个对象
        return {...value,done:doneOption} // 返回将done属性改编为doneOption的完整对象
      })
  },
   // 清除已经已经勾选的
   clearAllDoneFather(){
    this.todos=this.todos.filter((value)=>{
      // 假如说done值为false就不用过滤-保留,否则就需要过滤-不保留
      return value.done===false
    })
   }
  },
  watch:{// 我们初步设想的是利用,mounted目的是一上来就挂载上去。但是webStorage数据不会随着新增能新增...
  todos:{
    immediate: true,  // 若immediate为true则handle会在初始化时就会调用一次,以后就看firstName的改变了
    deep: true, //开启深度监视
    handler(newValue,oldValue){  //假如data是方法旧值获取不到(旧址也是新值),假如data是对象就能获取到旧值
        localStorage.setItem('arr_Object',JSON.stringify(newValue)); // 这里一定要转换为JSON字符串
      }
    }
  }
}
</script>
<style>
  /*base*/
  body {
    background: #fff;
  }
  .btn {
    display: inline-block;
    padding: 4px 12px;
    margin-bottom: 0;
    font-size: 14px;
    line-height: 20px;
    text-align: center;
    vertical-align: middle;
    cursor: pointer;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
    border-radius: 4px;
  }
  .btn-danger {
    color: #fff;
    background-color: #da4f49;
    border: 1px solid #bd362f;
  }
  .btn-danger:hover {
    color: #fff;
    background-color: #bd362f;
  }
  .btn:focus {
    outline: none;
  }
  .todo-container {
    width: 600px;
    margin: 0 auto;
  }
  .todo-container .todo-wrap {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
  }
</style>

Header.vue

$emit -> 属于vue实列的, vc是继承了vm
 add(){
        if(this.textA!==null){
           // 根据用户的输入生成一个todo对象
        const todo={id:Date.now(),name:this.textA,done:false}
        // 通知父App.vue添加这个数据
        this.$emit('addFatherA',todo)
        }
        this.textA=''
      }
<template>
  <div>
          <!-- 1.头部 -->
      <div class="todo-header">
        <input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="textA" @keyup.enter="add"/>
      </div>
  </div>
</template>
<script>
export default {
    name:'Header',
    data() {
      return {
        textA:''
      }
    },
    methods: {
      add(){
        if(this.textA!==null){
           // 根据用户的输入生成一个todo对象
        const todo={id:Date.now(),name:this.textA,done:false}
        // 通知父App.vue添加这个数据
        this.$emit('addFatherA',todo)
        }
        this.textA=''
      }
    },
}
</script>
<style scoped>
  /*header*/
  .todo-header input {
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
  }
  .todo-header input:focus {
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
  }
</style>

相关文章
|
22天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
119 1
|
1天前
|
JavaScript 安全 API
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
22 8
|
2天前
|
存储 设计模式 JavaScript
Vue 组件化开发:构建高质量应用的核心
本文深入探讨了 Vue.js 组件化开发的核心概念与最佳实践。
16 1
|
1月前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
2月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
57 1
vue学习第一章
|
2月前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
53 1
|
2月前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
47 1
vue学习第四章
|
2月前
|
JavaScript 前端开发 算法
vue学习第7章(循环)
欢迎来到瑞雨溪的博客,一名热爱JavaScript和Vue的大一学生。本文介绍了Vue中的v-for指令,包括遍历数组和对象、使用key以及数组的响应式方法等内容,并附有综合练习实例。关注我,将持续更新更多优质文章!🎉🎉🎉
41 1
vue学习第7章(循环)
|
2月前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
47 1
vue学习第九章(v-model)
|
2月前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
57 1
vue学习第十章(组件开发)