Vue---侦听器和组件的使用

127 阅读2分钟

侦听器-watch

介绍:想要侦听一个属性变化, 可使用侦听属性watch,可以侦听data/computed属性值改变

语法:

watch: {
    "被侦听的属性名" (newVal, oldVal){}
}

完整例子代码:

<template>
  <div>
    <p>num: <input type="text" v-model="num" /></p>
    <p>obj.name: <input type="text" v-model="obj.name" /></p>
    <p>obj.age: <input type="text" v-model="obj.age" /></p>
    <p>number: <input type="text" v-model="number" /></p>
    <h1>{{ number }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      num: "",
      obj: [
        {
          name: "悟空",
          age: "22",
        },
      ],
      number: "10",
      number2: 0,
    };
  },
  // 开始监听属性的变化
  watch: {
    num(newVal, oldVal) {
      // 以键值对的形式指定被监听字段:触发回调函数
      console.log(newVal, oldVal);
    },
    // 复杂类型无法直接接听
    obj: {
      // deep 可以监听到复杂数据内部的改变
      deep: true,
      handler(newV, oldV) {
        console.log(newV.name, oldV.age);
      },
    },
    // immediate 可以在页面进来时马上触发一次当前的监听回调函数
    number: {
      immediate: true,
      handler(aa) {
        this.number2 += aa;
      },
    },
  },
};
</script>

组件

1.为什么要用组件?

解决代码的冗余和重复,利于维护

2.概念

  1. 组件是可复用的 Vue 实例, 封装标签, 样式和JS代码
  2. 组件化 :封装的思想,把页面上可重用的部分封装为组件,从而方便项目的开发和维护
  3. 一个页面, 可以拆分成一个个组件,一个组件就是一个整体, 每个组件可以有自己独立的结构样式行为(html, css和js)

image-20220518155428000

3. 基础使用

  • 每个组件都是一个独立的个体(.vue结尾的文件)

  • 口诀: 哪部分标签复用, 就把哪部分封装到组件内

  • 注意:组件内template只能有一个根标签,且data必须是一个函数, 独立作用域

  • 使用步骤

    创建组件 components/ProItem.vue

    <template>
      <div>
        <ProItem :xo="item" v-for="(item, index) in list" :key="index" />
      </div>
    </template>
    
    <script>
    export default {
      components: {
        ProItem,
      },
      data() {
        return {
          list: ["悟空", "八戒", "唐曾", "沙和尚"],
        };
      },
    };
    </script>
    

    局部注册(局部和全部注册,按实际需求二选一即可,不可同时使用两种方式调用同一个vue文件)

    <script>
    // 局部注册引入方法
    // import(引入) ProItem(自定义组件名) from "@/components/ProItem.vue"
    //(@是指在 src 文件夹下开始找文件  相当于一个定点,@永远指向src/创建的组件)
    import ProItem from "@/components/ProItem.vue";
    export default {};
    </script>
    

    使用---局部注册

    <template>
      <div>
        <!-- 使用组件 -->
        <ProItem :xo="item" v-for="(item, index) in list" :key="index" />
      </div>
    </template>
    
    <script>
    // 局部注册
    import ProItem from "@/components/ProItem.vue";
    export default {
      components: {
        ProItem,
      },
      data() {
        return {
          list: ["悟空", "八戒", "唐曾", "沙和尚"],
        };
      },
    };
    </script>
    

    全局注册(全局入口在main.js, 在new Vue之上注册)

    // 全局注册 (一处定义到处使用)
    import Vue from 'vue'
    // 引入组件
    import ProItem from @/components/ProItem.vue'
    // 语法
    Vue.component("ProItem", ProItem) // 为了避免不必要的错误,一般命名都会跟随创建的 .vue文件名 来 命名
    

    使用---全局注册

    <!-- 单双标签都可以或者小写加-形式, 运行后, 会把这个自定义标签当做组件解析 -->
    <PannelG></PannelG>
    
    <PannelG/> <!-- 常用方式 -->
    
    <pannel-g></pannel-g>
    

4. scoped作用

  • 作用:解决多个组件样式名相同, 冲突问题
  • 使用:在style上加入scoped属性, 就会在此组件的标签上加上一个随机生成的data-v开头的属性,而且必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到
  • 完整代码
<!-- scoped 可以将当前的样式限定在这个文件内,最多可以穿透到下一层的根元素,其他不受影响 -->
<style scoped> </style>

image-20220518164038820

组件通信

父传子-props

  1. 父(App.vue) -> 子(ProItem.vue) 传值进入
<template>
  <div>
    <!-- 父传子第一步,父组件作为属性将数据交给子组件标签,属性名随便起 -->
    <!-- 子组件引入后,怎么渲染父组件的数据则由子组件决定 -->
    <!-- 如果我希望将一些数据传给子组件,以属性的形式传递即可,就好像以前class -->
    <!-- 父组件可以传任意数据,子组件不一定接收,需要接收的时候声明props -->
      <!-- 使用v-bind的方式 (:Prod="item):''/自定义变量名='要传过去的参数'-->
    <ProItem :ProItem="item" v-for="(item, index) in list" :key="index" />
  </div>
</template>

<script>
// 局部注册
import ProItem from "@/components/ProItem.vue";
export default {
  // 组件使用
  components: {
    ProItem,
  },
  data() {
    return {
      list: ["悟空", "八戒", "唐曾", "沙和尚"],
    };
  },
};
</script>
  1. 子组件声明一个可以接收的配置---props
<script>
export default {
  // 父传子第二步,子组件声明一个可以接收的配置 props
  // 父组件可以传数据,但是没有权限控制子组件怎么渲染
  // 如果子组件要接收父组件的数据,就要以字符串数组的形式声明props
   props: ["Prod"],
};
</script>
  1. 使用父组件传过来的数据
<template>
  <div>
    <!-- 第三步 使用父组件传过来的数据 -->
    <p>{{Prod}}</p>
  </div>
</template>

子传父

  1. 子组件出发自定义事件,传递参数(可选)
<template>
  <div>
    <p class="box">{{ title }} {{ price }} {{ msg }}</p>
    <button @click="change">砍价</button>
  </div>
</template>

<script>
export default {
  props: ["title", "price", "msg", "index"],
  methods: {
    // 子传父第一步 子组件出发自定义事件,传递参数(可选)
    change() {
      this.$emit("bargain", this.index, 2);
    },
  },
};
</script>
  1. 父组件监听子组件的自定义事件
<template>
  <div>
    <ProItem
      v-for="(obj, index) in list"
      :key="obj.id"
      :title="obj.proname"
      :price="obj.proprice"
      :msg="obj.info"
      :index="index"
      @bargain="check"
    />
    <!-- @bargain="check"  bargain为子组件传过来的组件名   check则是用来声明执行并接收的自定义命名-->
    <!-- 子传父第二步,父组件监听子组件的自定义事件  监听事件 -->
    <!-- 监听的自定义事件触发后,指定对应后续处理回调 -->
  </div>
</template>
  1. 开始执行子组件传过来值
<template>
  <div>
    <ProItem
      v-for="(obj, index) in list"
      :key="obj.id"
      :title="obj.proname"
      :price="obj.proprice"
      :msg="obj.info"
      :index="index"
      @bargain="check"
    />
    <!-- @bargain="check"  bargain为子组件传过来的组件名   check则是用来声明执行并接收的自定义命名-->
    <!-- 子传父第二步,父组件监听子组件的自定义事件  监听事件 -->
    <!-- 监听的自定义事件触发后,指定对应后续处理回调 -->
  </div>
</template>

<script>
// 局部注册
import ProItem from "@/components/ProItem.vue";
export default {
  components: {
    ProItem,
  },
  data() {
    return {
      list: [
        {
          id: 1,
          proname: "超级好吃的棒棒糖",
          proprice: 18.8,
          info: "开业大酬宾, 全场8折",
        },
        {
          id: 2,
          proname: "超级好吃的大鸡腿",
          proprice: 34.2,
          info: "好吃不腻, 快来买啊",
        },
        {
          id: 3,
          proname: "超级无敌的冰激凌",
          proprice: 14.2,
          info: "炎热的夏天, 来个冰激凌了",
        },
      ],
    };
  },
  // 第三步 开始执行子组件传过来值 this.$emit("bargain", this.index, 2)
  // index=this.index    price=2
  methods: {
    check(index, price) {
      if (this.list[index].proprice > price) {
        this.list[index].proprice = (this.list[index].proprice - price).toFixed(2);
      }
    },
  },
};
</script>

单向数据流

父到子的数据流向,就叫单向数据流。而在vue中,我们需要遵循的单向数据流原则

  1. 父组件的数据发生了改变,子组件会自动跟着变
  2. 子组件不能直接修改父组件传递过来的props,props是只读的
  3. 父组件传给子组件的是一个对象,子组件修改对象的属性,是不会报错的,对象是引用类型, 互相更新