父传子

父组件给子组件传值

App.vue

<template>
  <div class="container">
    <Son :money="money" />
    <h1>App</h1>
    {{ money }}
  </div>
</template>

<script>
import { ref } from "vue";
import Son from "./Son.vue";
export default {
  name: "App",
  components: {
    Son,
  },
  setup() {
    const money = ref(10);
    return { money };
  },
};
</script>

Son.vue

<template>
  <div class="container">
    <h1>Son</h1>
    {{ money }}
  </div>
</template>

<script>
export default {
  name: "Son",
  props: {
    money: {
      type: Number,
      default: 0,
    },
  },
  setup(props) {
    console.log(props.money);
  },
};
</script>

子传父

App.vue

<template>
  <div class="container">
    <Son @changeMoney="newMoney" />
    <h1>App</h1>
    {{ money }}
  </div>
</template>

<script>
import { ref } from "vue";
import Son from "./Son.vue";
export default {
  name: "App",
  components: {
    Son,
  },
  setup() {
    const money = ref(10);
    const newMoney = (change) => {
      console.log(change); // 50
    };
    return { money, newMoney };
  },
};
</script>

Son.vue

<template>
  <div class="container">
    <h1>Son</h1>
    {{ money }}
  </div>
</template>

<script>
export default {
  name: "Son",
  props: {
    money: {
      type: Number,
      default: 0,
    },
  },
  setup(props, { emit }) {
    emit("change-money", 50);
  },
};
</script>

依赖注入

provide函数提供数据和函数给后代组件使用

inject函数给当前组件注入provide提供的数据和函数

App.vue

<template>
  <div class="container">
    <h1>App {{ money }} <button @click="sendMoney">sendMoney</button></h1>
    <Son />
  </div>
</template>

<script>
import { provide, ref } from "vue";
import Son from "./Son.vue";
export default {
  name: "App",
  components: {
    Son,
  },
  setup() {
    const money = ref(10);
    // 将数据提供给后代组件
    provide("CNY", money);
    // 修改数据
    const changeMoney = (v) => {
      money.value = v;
    };
    provide("changeMoney", changeMoney);

    const sendMoney = () => {
      money.value += 1;
    };
    return { money, sendMoney };
  },
};
</script>

Son.vue

<template>
  <div class="container">
    <h2>Son {{ money }}</h2>
    <grand-son />
  </div>
</template>

<script>
import { inject } from "vue";
import GrandSon from "./GrandSon.vue";
export default {
  components: { GrandSon },
  name: "Son",
  setup() {
    const money = inject("CNY");
    return { money };
  },
};
</script>

GrandSon.vue

<template>
  <div class="container">
    <h3>GrandSon {{ money }}</h3>
    <button @click="fn">9999 money</button>
  </div>
</template>

<script>
import { inject } from "@vue/runtime-core";
export default {
  setup() {
    const money = inject("CNY");
    const changeMoney = inject("changeMoney");
    const fn = () => {
      changeMoney(9999);
    };
    return { money, fn };
  },
};
</script>

v-model 语法糖

参考文章 vue3 v-model的使用open in new window

v-model在vue2.x中的使用方式

我们首先看一下vue2.x中v-model的使用。

<ChildComponent v-model = "title />

它实际上是下面这种写法的简写:

<ChildComponent :value = "title"  @input = "title = $event" />

也就是说,它实际上是传递一个属性value,然后接收一个input事件。

下面这种写法

<Son :modelValue="count" @update:modelValue="count = $event" />

可以简写成

<Son v-model="count" />

App.vue

<template>
  <div class="container">
    <h1>App {{ count }}</h1>
    <!-- <Son :modelValue="count" @update:modelValue="count = $event" /> -->
    <Son v-model="count" />
  </div>
</template>

<script>
import { ref } from "vue";
import Son from "./Son.vue";
export default {
  name: "App",
  components: {
    Son,
  },
  setup() {
    const count = ref(10);

    return { count };
  },
};
</script>

Son.vue

<template>
  <div class="container">
    <h2>Son {{ modelValue }} <button @click="fn">change count</button></h2>
  </div>
</template>

<script>
export default {
  name: "Son",
  props: {
    modelValue: {
      type: Number,
      default: 0,
    },
  },
  setup(props, { emit }) {
    const fn = () => {
      emit("update:modelValue", 100);
    };
    return { fn };
  },
};
</script>

mixin

混入 (mixin) 提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

全局混入

每个组件都会混入

import { createApp } from "vue";
import App from './App.vue';

const app = createApp(App)
app.mixin({
    // 在DOM准备好之后打印一句话
    mounted() {
        // $el 组件的根元素
        console.log(this.$el, "DOM准备好了");
    }
})
app.mount('#app')

局部混入

实现一个关注功能

mixins.js

// 关注
export const followMixin = {
  data() {
    return {
      loading: false,
      _disabled: false
    }
  },
  methods: {
    followFn() {
      this._disabled = true
      // 模拟请求
      setTimeout(() => {
        this.loading = !this.loading
        this._disabled = false
      }, 2000)
    }
  }
}

App.vue

<template>
  <div class="container">
    <h1>
      App
      <button @click="followFn" :disabled="_disabled">
        {{ loading ? "已关注" : "关注" }}
      </button>
    </h1>
    <Son />
  </div>
</template>

<script>
import Son from "./Son.vue";
import { followMixin } from "./mixins";
export default {
  name: "App",
  components: {
    Son,
  },
  mixins: [followMixin],
};
</script>

Son.vue

<template>
  <div class="container">
    <h1>
      Son
      <button @click="followFn" :disabled="_disabled">
        {{ loading ? "已关注" : "关注" }}
      </button>
    </h1>
  </div>
</template>

<script>
import { followMixin } from "./mixins";
export default {
  name: "Son",
  mixins: [followMixin],
};
</script>