首页 > 其他分享 >day04

day04

时间:2024-02-19 22:56:17浏览次数:20  
标签:refs value day04 props 组件 model data

day04

目录

scoped 解决样式冲突

  • 因为只写 <style> 的话是全局样式,影响所有组件,而 scoped 下样式只作用于当前组件

默认情况

  • 写在组件中的样式会全局生效

    • 因此很容易造成多个组件之间的样式冲突问题
  • 全局样式:默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响

    • 子组件的也会影响到父组件和兄弟组件
  • 局部样式:可以给组件加上 scoped 属性,可以让样式只作用于当前组件

scoped 原理

  • 当前组件内标签都被添加 data-v-hash值 的属性

    • 不同组件有不同的哈希值就可以来区分了
  • css 选择器都被添加 data-v-hash值 的属性选择器

    • F12 查看样式就会发现标签的后面都加了 [data-v-hash值](被自动处理,添加上了属性选择器)

      68230651737

  • 最终效果:必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到

data 必须是一个函数

  • 一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象

    • 即:data() { return { ...... }}
  • 每次创建新的组件实例,都会新执行一次 data 函数,得到一个新对象

    • 即一个父组件中引入使用了若干个子组件,每个子组件的 data 互不影响、相互独立
    • 若是还是写对象 data: { ...... } 就会报错

组件通信

  • 组件通信,就是指组件与组件之间的数据传递

  • 组件的数据本是独立的,无法直接访问其他组件的数据

  • 想使用其他组件的数据,就需要组件通信

通信解决方案

  • 下图三种

68231811109

父子通信流程

  1. 父组件通过 props 将数据传递给子组件
    • 父组件 <子组件 :xxx="data里return的数据"></子组件>
    • 子组件 props:['xxx'] 便可以获取使用 xxx 值了
  2. 子组件利用 $emit 通知父组件修改更新
    • 子组件加个事件触发,在事件里 this.$emit('yyy', '想传的值')
    • 父组件 @yyy="父组件里的事件名" 获取,父组件里的事件名(值){ 就可以对值进行修改了 }

props

  • Props 定义:组件上注册的一些自定义属性

  • Props 作用:向子组件传递数据

特点

  1. 可以传递任意数量的 prop
  2. 可以传递任意类型的 prop

props 校验

作用

  • 为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示,帮助开发者,快速发现错误

语法

  • 类型校验
  • 非空校验
  • 默认值
  • 自定义校验

props 校验完整写法

props: {
  校验的属性名: {
    type: 类型,  // Number String Boolean ...
    required: true, // 是否必填
    default: 默认值, // 默认值
    validator (value) { // value就是传来的值
      // 自定义校验逻辑
      return 布尔类型
    }
  }
},

注意

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

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

props & data、单向数据流

共同点

  • 都可以给组件提供数据

区别

  • data 的数据是自己的

    • 随便改
  • prop 的数据是外部的

    • 不能直接改,要遵循单向数据流

单向数据流:

  • 父级 props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的

非父子通信 — event bus 事件总线

作用

  • 非父子组件之间,进行简易消息传递(复杂场景还是:Vuex)

步骤

  1. 创建一个都能访问的事件总线(空的 Vue 实例)

    import Vue from 'vue'
    const Bus = new Vue() // 创建一个空的实例
    export default Bus // 导出,使其他组件可以引入
    
    • 最好可以新建一个文件,在新文件里创建 js 文件来放空的 Vue 实例部分
    • Bus 就是一个中间总线,使不相关的 A 和 B 组件有了相互的响应
  2. A 组件(接受方),监听 Bus 的 $on 事件

    created () { // 一进页面就监听
      Bus.$on('sendMsg', (msg) => { // $on 就是进行事件监听
        this.msg = msg
      })
    }
    
  3. B 组件(发送方),触发 Bus 的 $emit 事件(例如 @click 触发)

    Bus.$emit('sendMsg', '这是一个消息')
    
    • 触发此事件后,任何监听 sendMsg 这一个消息的都能后收到做出操作
  4. 这样在 B 点击事件触发后,A 组件就会更新信息为 B 的 '这是一个消息'

    68232839240

非父子通信 — provide & inject

作用

  • 跨层级共享数据
  • 实际还是有所联系,只不过可能是爷孙而非父子关系

场景

68232950551

语法

  1. 父组件 provide 提供数据

    • vue3 就又是不同的写法了

      provide('changeDiv', () => { 触发自定义事件() })

    export default {
      provide () {
        return {
           // 普通类型【非响应式】
           color: this.color, 
           // 复杂类型【响应式】
           userInfo: this.userInfo, 
        }
      }
    }
    
  2. 子 / 孙组件 inject 获取数据

    • vue3 就又是不同的写法了 const changeDiv = inject('changeDiv'),自定义事件触发 changeDiv()
    export default {
      inject: ['color','userInfo'],
      created () {
        console.log(this.color, this.userInfo)
      }
    }
    

注意

  • provide 提供的简单类型的数据不是响应式的,复杂类型数据是响应式(所以还是推荐提供复杂类型数据)
  • 子 / 孙组件通过 inject 获取的数据,不能在自身组件内修改

v-model

原理

  • v-model 本质上是一个语法糖(代码语法的简写)。例如应用在输入框上,就是 value 属性和 input 事件的合写

    <template>
      <div id="app" >
        <input v-model="msg" type="text">
    
        <input :value="msg" @input="msg = $event.target.value" type="text">
      </div>
    </template>
    

作用

  • 提供数据的双向绑定

  • 数据变,视图跟着变 :value

  • 视图变,数据跟着变 @input

注意

  • 在模板中,用来获取事件的形参的是 $event
  • 放进 @input 里,形参就是事件对象 ee.target 就是触发事件的事件源 —— 输入框,.value 拿到输入框的值,然后实时地赋给 msg

v-model 使用在其他表单元素上的原理

  • 不同的表单元素, v-model 在底层的处理机制是不一样的。比如给 checkbox 使用 v-model
    • 底层处理的是 checked 属性和 change 事件
  • 但设计思路一样

表单类组件封装

需求目标

  • 父表单组件里有个下拉的子组件

    • 子组件的下拉数据来自于父
    • 而下拉是更改,但子本不能改父传来的值
    • 所以要 v-model 拆解开,取其底层来绑定数据
  • 实现子组件和父组件数据的双向绑定

代码演示

  • 父 App.vue
<template>
  <div class="app">
    <!--  这里直接用 $event 就可以拿到子传来的形参:e.target.value  -->
    <BaseSelect :cityId="selectId" @事件名="selectedId = $event"></BaseSelect>
  </div>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
  data() {
    return {
      selectId: '102',
    }
  },
  components: {
    BaseSelect,
  },
}
</script>

<style>
</style>
  • 子 BaseSelect.vue
<template>
  <div>
    <select :value="cityId" @change="handleChange">
      <!--  这里就不能用v-model,但是可以用拆解后的样式实现  -->
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">武汉</option>
      <option value="104">广州</option>
      <option value="105">深圳</option>
    </select>
  </div>
</template>

<script>
export default {
  props: {
    cityId: String
  },
  methods: {
    handleChange(e){
      // 每次把新值传给父
      this.$emit('事件名', e.target.value)
    }
  }
}
</script>

<style>
</style>

v-model 简化上述的代码

目标

  • 父组件通过 v-model 简化代码,实现子组件和父组件数据双向绑定

如何简化

  • v-model 其实就是 :value@input 事件的简写

  • 子组件:props 通过 value 接收数据,事件触发 input

  • 父组件:v-model 直接绑定数据

代码示例

  • 子组件
<select :value="value" @change="handleChange">...</select>
props: {
	<!--  这里的值得固定是 value 了  -->
  value: String
},
methods: {
  handleChange (e) {
    <!--  这里也得固定是 input 事件名了  -->
    this.$emit('input', e.target.value)
  }
}
  • 父组件
<BaseSelect v-model="selectId"></BaseSelect>
<!--  :value + @input  -->

.sync 修饰符

作用

  • 可以实现子组件与父组件数据的双向绑定,简化代码

    • prop 是自定义的,非固定为 value
    • 需要传的并不全是 value 类型的,例如弹窗类的组件都是用 visible 属性双向绑定传布尔值的
  • 简单理解:子组件可以修改父组件传过来的 props 值

本质

  • .sync 修饰符就是 :属性名@update:属性名 合写

语法

  • 父组件

    // 	.sync写法
    <BaseDialog :visible.sync="isShow" />
    
    // 等价于:
    <BaseDialog 
      :visible="isShow" 
      @update:visible="isShow = $event" 
    />
    
  • 子组件(就需要配合父组件固定写为 visiable 和 update:visiable 了)

    props: {
      visible: Boolean
    },
    
    // 方法里
    this.$emit('update:visible', false)
    

总结

  • 当想父子组件双向绑定更新,但传值不是 value(就没法用 v-model),而是别的类型的 prop 的话,就用 xxx属性名.sync="" 来绑定,子组件用 xxx属性名update:xxx属性名 配合

ref 和 $refs

作用

  • 利用 ref$refs 可以用于获取 dom 元素或组件实例

特点

  • 查找范围:当前组件内(更精确稳定)

语法

  1. 给要获取的盒子添加 ref 属性

    <div ref="chartRef">我是渲染图表的容器</div>
    
  2. 获取时,在恰当的时候(dom 渲染完之后)通过 this.$refs.chartRef 获取

    mounted () { 
      console.log(this.$refs.chartRef)
    }
    

代码示例 —— 获取 dom 元素

  • App.vue
<template>
  <div class="app">
    <div class="base-chart-box">不需要的但class相同的div</div>
    <BaseChart></BaseChart>
  </div>
</template>

<script>
import BaseChart from './components/BaseChart.vue'
export default {
  components:{
    BaseChart
  }
}
</script>
  • BaseChart.vue
<template>
  <div class="base-chart-box" ref="baseChartBox">正确需要的子组件盒子</div>
</template>

<script>
// yarn add echarts 或者 npm i echarts
import * as echarts from 'echarts'

export default {
  mounted() {
    // 基于准备好的dom,初始化echarts实例
    // const myChart = echarts.init(document.querySelect('.base-chart-box'))
    const myChart = echarts.init(this.$refs.mychart) // 更好的方法
    // 绘制图表
    myChart.setOption({
      title: {...},
      tooltip: {...},
      xAxis: {...},
      yAxis: {...},
      series: [...],
      // ......
    })
  },
}
</script>
  • 原始的 document.querySelect('.base-chart-box') 查找的是整个页面,若是有多个 class 为 base-chart-box 的 div 盒子的话(例如在父组件里就有),就会找第一个盒子(但所需要的是子组件里本组件的 div 盒子)

代码示例 —— 获取组件实例

  • 在子组件 BaseForm 中有一个方法,父组件也想直接使用这个方法:
    • 先给父组件调用子组件的标签加上 ref:<BaseForm ref="baseForm"></BaseForm>
    • 在父组件里就可以使用 this.$refs.baseForm 获取到组件实例,可以打印出来看看,内部展开就有子组件的方法,那就可以直接调用了
    • 在父组件的方法里调用子组件已有的方法:this.$refs.baseForm.任一方法名()

异步更新 & $nextTick

需求

  • 编辑标题, 编辑框自动聚焦:
    • 点击编辑,显示编辑框
    • 显示的时候,立刻让编辑框获取焦点

代码实现

<template>
  <div class="app">
    <div v-if="isShowEdit">
      <input type="text" v-model="editValue" ref="xxinp" />
      <button>确认</button>
    </div>
    
    <div v-else>
      <span>{{ title }}</span>
      <button @click="editFn">编辑</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: '大标题',
      isShowEdit: false,
      editValue: '',
    }
  },
  methods: {
    editFn() {
        // 显示输入框
        this.isShowEdit = true  
        // 用ref获取元素,从而获取焦点
        this.$refs.xxinp.focus() 
    }  
  },
}
</script> 

问题

  • 上述代码看似没问题,但实际不是如此
  • " 显示之后 ",立刻获取焦点是不能成功的
  • 原因:Vue 是异步更新 DOM(为了提升性能)
    • 虽然显示了,但 dom 其实还没真正解析渲染完成

解决方案

  • $nextTick:等 DOM 更新后,才会(立刻)触发执行此方法里的函数体

  • 语法:this.$nextTick(函数体)

    methods: {
      editFn() {
        // 显示输入框
        this.isShowEdit = true  
        // 使用$nextTick
        this.$nextTick(() => {
        	this.$refs.inp.focus()
      	})
      }  
    },
    
    // 虽然用setTimeout(() => { this.$refs.inp.focus() }, 1000)一般也没有问题,一秒钟足够渲染成功了,但是 ——> 还是$nextTick更精准(等 DOM 更新后就立刻执行函数体)
    
  • 注意:$nextTick 内的函数体一定是箭头函数,这样才能让函数内部的 this 指向 Vue 实例

标签:refs,value,day04,props,组件,model,data
From: https://www.cnblogs.com/zhu-ya-zhu/p/18022114

相关文章

  • day04_操作系统入门
    今日笔记学操作系统基础概念linux系统linux系统(centos)+vmware安装起来(网络配置,磁盘分区)ubuntu安装xshell服务器的远程连接服务器网站的前后端,数据库app的前后端,数据库微信、腾讯微信的服务器移动端设备上,安装的微信客户端在线笔记笔记对运维来说,就是一个宝藏,mar......
  • MetaGPT day04 MetaGPT ActionNode
    ActionNode说明文档导读#什么是ActionNode?1.ActionNode是Action的通用化抽象2.ActionNode是SOP的最小单元#ActionNode是Action的通用化抽象:反推可得知Action不够通用化?也就是说ActionNode的粒度比action更细? Action-粒度更细->ActionNode#Actio......
  • day04 dos
    dos原理相对路径和绝对路径dos常见指令echo/type:创建有内容/空文件......
  • 代码随想录day04 两两交换链表中的节点 删除链表的倒数第N个节点 链表相交 环形链表
    两两交换链表中的节点题目:这题画一下链表会比较清晰写写画画指针位置很快就可以写出来一开始以为一个tmp就够用了写着写着发现需要多一个代码:删除链表的倒数第N个节点:没什么思路只好先看看视频思路视频思路很简单也很清晰只需要两个指针一快一慢两指针的间......
  • day04 进制和编码
    day04进制和编码1.pythont代码的运行方式脚本时交互式2.进制二进制(字符串)八进制(整型)十进制(字符串)十六进制(字符串)2.1进制转换v1=bin(35)#十进制转换成二进制v2=oct(35)#十进制转换成八进制v3=hex(35)#十进制转换成十六进制print(v1,v2,v3)结果输......
  • Day04运算符
    基本运算符//前四个,必须掌握!!!!!!!!!!!!!!!算木运算符:+,-,*,/,%,++,--赋值运算符=关系运算符:>,<,>=,<=,==,!=,instanceof运算符:&&,||,!//下面的,了解就行--------------------位运算符:&,|,^,~,>>、<<,>>>......
  • Day04常量
    常量常量(Constant):初始化(initialize)后不能再改変的値!不会変动的値。所谓常量可以理解成一种特殊的変量,它的値被定后,在程序运行程中不允许被改変。//finalfinal常量名=値;finaldoublePI=3.14;System.out.println("==============================");public......
  • Day04类型转换
    类型转换注意点:1.不能对布尔值进行转换2.不能把对象类型转换为不相干的类型3.在把高容量转换到低容量的时候,强制转换4.转换的时候可能存在内存溢出,或者精度问题!高转低,强制转换;低转高,自动转换低------------------------------------------->高byte,short,char->int-......
  • Day04
    Day04注释注释的分类单行注释//注释信息多行注释/*注释信息*/文档注释/**注释信息**/注释的注意事项注释的内容不参与编译也不参与运行的多行注释会以最近的"*/"作为注释的结尾,不管是单行注释还是多行注释,在书写的时候都不要嵌套关键字关键字的特点......
  • day04
    进制在计算机中,任何数据都是以二进制数据来进行存储的.常见的进制有以下几种类型:1.二进制2.八进制3.十进制4.十六进制![](C:\Users\chent\Pictures\Screenshots\屏幕截图2023-12-02142653.png)进制转换公式:系数*基数的权次幂相加![截图](C:\Users\chent\Pictures......