Vue 1.28

一、组件通信

**1.**什么是prop

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

作用:向子组件传递数据

javascript 复制代码
/* App.vue */
<template>
  <div class="app">
    <UserInfo 
    :username="username"
    :age="age"
    :isSingle="isSingle"
    :car="car"
    :hobby="hobby"
    ></UserInfo>
  </div>
</template>

<script>
import UserInfo from './components/UserInfo.vue'
export default {
  data() {
    return {
      username: '小帅',
      age: 28,
      isSingle: true,
      car: {
        brand: '宝马',
      },
      hobby: ['篮球', '足球', '羽毛球'],
    }
  },
  components: {
    UserInfo,
  },
}
</script>

<style>
</style>
javascript 复制代码
/* UserInfo.vue */
<template>
  <div class="userinfo">
    <h3>我是个人信息组件</h3>
    <div>姓名:{{ username }}</div>
    <div>年龄:{{ age }}</div>
    <div>是否单身:{{ isSingle ? '是' : '否' }}</div>
    <div>座驾:{{ car.brand }}</div>
    <div>兴趣爱好 {{ hobby.join(' , ') }}</div>
  </div>
</template>

<script>
export default {
  props: ['username', 'age', 'isSingle', 'car', 'hobby']
}
</script>

<style>
.userinfo {
  width: 300px;
  border: 3px solid #000;
  padding: 20px;
}
.userinfo > div {
  margin: 20px 10px;
}
</style>

**2.**prorps校验

语法:

javascript 复制代码
/* App.vue */
<template>
  <div class="app">
    <BaseProgress :w="width"></BaseProgress>
  </div>
</template>

<script>
import BaseProgress from './components/BaseProgress.vue'
export default {
  data() {
    return {
      width: 30,
    }
  },
  components: {
    BaseProgress,
  },
}
</script>

<style>
</style>
javascript 复制代码
/* BaseProgress.vue */
<template>
  <div class="base-progress">
    <div class="inner" :style="{ width: w + '%' }">
      <span>{{ w }}%</span>
    </div>
  </div>
</template>

<script>
export default {
  // props: ["w"],

  // 1.基础写法(类型校验)
  // props: {
  //   w: Number // Number String Boolean Array Object function 
  // }


  // 2.完整写法(类型、是否必填、默认值、自定义校验)
  props: {
    w: {
      type: Number,
      // required: true
      default: 0,  // 默认值
      validator (value) {
        // console.log(value)
        if (value >= 0 && value <= 100) {
          return true
        } else {
          console.error('传入的 prop w. 必须是0 ~ 100')
          return false
        }
      }
    }
  }
}
</script>

<style scoped>
.base-progress {
  height: 26px;
  width: 400px;
  border-radius: 15px;
  background-color: #272425;
  border: 3px solid #272425;
  box-sizing: border-box;
  margin-bottom: 30px;
}
.inner {
  position: relative;
  background: #379bff;
  border-radius: 15px;
  height: 25px;
  box-sizing: border-box;
  left: -3px;
  top: -2px;
}
.inner span {
  position: absolute;
  right: 0;
  top: 26px;
}
</style>

3. prop 和 data、单向数据流

javascript 复制代码
/* App.vue */
<template>
  <div class="app">
    <BaseCount 
    @changeCount="handleChange"
    :count="count">
    </BaseCount>
  </div>
</template>

<script>
import BaseCount from './components/BaseCount.vue'
export default {
  components:{
    BaseCount
  },
  data(){
    return {
      count:100
    }
  },
  methods:{
    handleChange (newCount) {
      // console.log(newCount)
      this.count = newCount
    }
  }
}
</script>

<style>

</style>
javascript 复制代码
/* BasCount.vue */
<template>
  <div class="base-count">
    <button @click="count--">-</button>
    <span>{{ count }}</span>
    <button @click="count++">+</button>
  </div>
</template>

<script>
export default {
  // 1.自己的数据随便修改  (谁的数据 谁负责)
  // data () {
  //   return {
  //     count: 100,
  //   }
  // },


  // 2.外部传过来的数据 不能随便修改
  props: {
    count: Number
  },
  methods: {
    handleAdd () {
      // 子传父 this.$emit(事件名, 参数)
      this.$emit('changeCount', this.count + 1)
    },
    handleSub () {
      this.$emit('changeCount', this.count - 1)
    }
  }
}

// 单向数据流,父组件的prop更新,会单向向下流动,影响到子组件
</script>

<style>
.base-count {
  margin: 20px;
}
</style>

二、综合案例

**1.**总结

2. 非父子通信 (拓展) - event bus 事件总线

作用:非父子组件之间,进行简易消息传递。(复杂场景 → Vuex)

3. 非父子通信 (拓展) - provide & inject

javascript 复制代码
<template>
  <div class="app">
    我是APP组件
    <button @click="change">修改数据</button>
    <SonA></SonA>
    <SonB></SonB>
  </div>
</template>

<script>
import SonA from './components/SonA.vue'
import SonB from './components/SonB.vue'
export default {
  provide () {
    return {
      color: this.color, // 简单类型(非响应式)
      userInfo: this.userInfo // 复杂类型(想要式) - 推荐
    }
  },
  data() {
    return {
      color: 'pink', 
      userInfo: { 
        name: 'jtl',
        age: 18,
      },
    }
  },
  methods: {
    change () {
      // this.color = 'green'
      this.userInfo.name = 'htl'
    }
  },
  components: {
    SonA,
    SonB,
  },
}
</script>

<style>
.app {
  border: 3px solid #000;
  border-radius: 6px;
  margin: 10px;
}
</style>
javascript 复制代码
<template>
  <div class="grandSon">
    我是GrandSon
   {{ color }} - {{ userInfo.name }} - {{ userInfo.age}}
  </div>
</template>

<script>
export default {
  inject: ['color', 'userInfo']
}
</script>

<style>
.grandSon {
  border: 3px solid #000;
  border-radius: 6px;
  margin: 10px;
  height: 100px;
}
</style>

三、进阶语法

1. v-model 原理

(1)原理:v-model本质上是一个语法糖。如应用在输入框上,就是 value属性和input事件的合写

(2)作用:提供数据的双向绑定

(3)注意:$event 用于在模板中,获取事件的形参

javascript 复制代码
<template>
  <div class="app">
    <input v-model="msg1" type="text" />
    <br />
    <!-- 模板中获取事件的形参 => $event 获取 -->
    <input :value="msg2" @input="msg2 = $event.target.value" type="text" >
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg1: '',
      msg2: '',
    }
  },
}
</script>

<style>
</style>

2. 表单类组件封装 & v-model 简化代码

(1)表单类组件封装 => 实现 子组件 和 父组件数据 的双向绑定

javascript 复制代码
<template>
  <div class="app">
    <BaseSelect
      :cityId="selectId"
      @changeId="selectId = $event"
    ></BaseSelect>
  </div>
</template>

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

<style>
</style>
javascript 复制代码
<template>
  <div>
    <select :value="cityId" @change="handleChange">
      <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) {
      // console.log(e.target.value)
      this.$emit('changeId', e.target.value)
    }
  }
}
</script>

<style>
</style>

(2)父组件 v-model 简化代码,实现 子组件 和 父组件数据 双向绑定

javascript 复制代码
<template>
  <div class="app">
    <!-- v-model => :value + @input -->
    <BaseSelect
      v-model="selectId"
    ></BaseSelect>
  </div>
</template>

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

<style>
</style>
javascript 复制代码
<template>
  <div>
    <select :value="value" @change="handleChange">
      <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: {
    value: String
  },
  methods: {
    handleChange (e) {
      this.$emit('input', e.target.value)
    }
  }
}
</script>

<style>
</style>

3. .sync 修饰符

(1)作用:可以实现 子组件 与 父组件数据 的 双向绑定,简化代码

(2)特点:prop属性名,可以自定义,非固定为 value

(3)场景:封装弹框类的基础组件, visible属性 true显示 false隐藏

(4)本质:就是 :属性名 和 @update:属性名 合写

4. .ref 和 $refs

作用:利用 ref 和 $refs 可以用于 获取 dom 元素, 或 组件实例

5. Vue异步更新、$nextTick

javascript 复制代码
<template>
<!-- 编辑状态 -->
  <div class="app">
    <div v-if="isShowEdit">
      <input type="text"  v-model="editValue" ref="inp" />
      <button>确认</button>
    </div>
    <!-- 默认状态 -->
    <div v-else>
      <span>{{ title }}</span>
      <button @click="handleEdit">编辑</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: '大标题',
      isShowEdit: false,
      editValue: '',
    }
  },
  methods: {
   handleEdit () {
    // 1. 显示输入框 (异步 dom 更新)
    this.isShowEdit = true
    // 2. 让输入框获取焦点 ($nextTick等 dom 更新完,立刻执行准备的函数体)
    this.$nextTick(() => {
      // console.log(this.$refs.inp)
      this.$refs.inp.focus()
    })

    // setTimeout(() => {
    //   this.$refs.inp.focus()
    // }, 1000)
   }
  },
}
</script>

<style>
</style>
相关推荐
鹓于2 小时前
Excel一键生成炫彩二维码
开发语言·前端·javascript
siwangdexie_new2 小时前
html格式字符串转word文档,前端插件( html-docx-js )遇到兼容问题的解决过程
前端·javascript·html
子春一2 小时前
Flutter for OpenHarmony:构建一个智能长度单位转换器,深入解析 Flutter 中的多字段联动、输入同步与工程化表单设计
开发语言·javascript·flutter
2601_949613022 小时前
flutter_for_openharmony家庭药箱管理app实战+用药提醒列表实现
服务器·前端·flutter
利刃大大2 小时前
【Vue】scoped作用 && 父子组件通信 && props && emit
前端·javascript·vue.js
-凌凌漆-2 小时前
【Vue】Vue3 vite build 之后空白
前端·javascript·vue.js
心柠2 小时前
前端工程化
前端
摘星编程2 小时前
用React Native开发OpenHarmony应用:useImperativeHandle暴露实例方法
javascript·react native·react.js
沐雪架构师2 小时前
核心组件2
前端