• vue3 Component API


    项目代码仓库:https://github.com/chenfenbgin/component-api
    注:Component API也是用来替代Mixin的。

    一、Mixin 和 extends

    1、Mixin在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    2、extends

    在这里插入图片描述

    二、Component Api

    在这里插入图片描述

    在这里插入图片描述

    1、setup的参数

    在这里插入图片描述

    <template>
      <div id="app">
        home page
        <!-- 这里使用父组件传过来的值 -->
        <h2>{{ message }}</h2>
        <h2>{{ title }}</h2>
        <h2>当前计算: {{ counter }}</h2>
        <!-- <button @click="btnClick">按钮</button> -->
      </div>
    </template>
    
    <script type="text/javascript">
    export default {
      name: "app",
    
      props: {
        message: {
          type: String,
          required: true,
        },
      },
    
      // setup函数有哪些参数?
      // setup函数有什么样的返回值
    
      // setup写法一:两个参数
      /**
       * 参数一: props, 父组件传递过来的属性,这里如果想要使用props参数,必须这么写
       */
      // setup(props, context) {
      //   // setup里面不能使用this,无法获取this.props
      //   // console.log(this.props);
      //   console.log("props", props.message);
    
      //   // 我们不可以这么发出事件
      //   // this.$emit()
      //   console.log('id, class', context.attrs.id, context.attrs.class);
      //   console.log('slots', context.slots);
      //   console.log('emit', context.emit);
      // },
    
      // 之前的发出事件,写了setup,以后就不再这么写了,当然,也不可以在setup中直接使用this.$emit()
      // methods:{
      //   btnClick(){
      //     this.$emit("")
      //   }
      // }
    
      // setup写法二:对象的解构,如果没有需要,直接对content进行解构获取只需要的属性即可
      setup(props, { attrs, slots, emit }) {
        console.log(props.message);
        console.log(attrs.id, attrs.class);
        console.log(slots);
        console.log(emit);
    
        // 这里可以返回数据,就不需要data(){return{}},
        return {
          title: "hello home",
          counter: 100,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    2、setup的返回值

    在这里插入图片描述

    <template>
      <div id="app">
        home page
        <h2>{{ message }}</h2>
    
        <h2>{{ title }}</h2>
        <h2>当前计算: {{ counter }}</h2>
        <button @click="increment">+1</button>
      </div>
    </template>
    
    <script type="text/javascript">
    export default {
      name: "app",
    
      props: {
        message: {
          type: String,
          required: true,
        },
      },
    
      setup() {
        let counter = 100;
        // 局部函数
        const increment = () => {
          console.log("increment");
          counter++;
          // y有打印, 但是没刷新, 因为没加入响应式,因为data(){return{}}返回的数据会经过reactive函数处理, 他是响应式的
          console.log("counter", counter);
        };
    
        return {
          title: "hello home",
          counter,
          increment,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    3、setup中的this问题

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    4、reactive Api

    在这里插入图片描述

    5、ref Api

    在这里插入图片描述

    注:模板中的解包,是一个浅层解包

    在这里插入图片描述

    <template>
      <div>
        Home Page
        <h2>{{ message }}</h2>
    
        <!-- 当我们在template模板中使用ref对象,它会自动进行解包操作, 不需要写.value -->
        <h2>当前计数: {{ counter }}</h2>
    
        <!-- ref的解包只能是一个浅层解包(info是一个普通的js对象) -->
        <h2>当前计数:{{ info.counter.value }}</h2>
    
        <!-- 当如果最外层包裹的是一个reactive可响应式对象,那么内容可以解包 -->
        <h2>当前计数:{{ reactiveInfo.counter }}</h2>
        <button @click="increment">+1</button>
      </div>
    </template>
    
    <script>
    import { ref, reactive } from "vue";
    
    export default {
      props: {
        message: {
          type: String,
          required: true,
        },
      },
      setup() {
        // reactive API对传入的类型是有所限制的,要求我们必须传入一个对象或者数组类型,如果我们传入一个基本类型(String、Number、Boolean)会报一个警告
        // const counter = reactive(100) //报警告, 要使用Ref API, ref会返回一个可变的响应式对象,该对象作为一个响应式的引用,维护它内部的值,
    
        // counter = 100; //100是数值类型
        // 100变成了一个ref的可响应式的引用
        let counter = ref(100);
    
        // 情况1:无法解包:模板中无法通过{{info.counter}}进行解包的,这只是浅层解包
        const info = {
          counter,
        };
    
        // 情况2:可以解包:
        const reactiveInfo = reactive({
          counter,
        });
        const increment = () => {
          counter.value++;
          console.log(counter.value);
        };
    
        return {
          counter,
          increment,
          info,
          reactiveInfo,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    6、readonly Api

    在这里插入图片描述
    在这里插入图片描述

    注:给子组件传过去的,应该是一个响应式对象

    <template>
      <div>
        <button @click="updateState">修改状态</button>
      </div>
    </template>
    
    <script>
    import { reactive, readonly } from "vue";
    
    export default {
      setup() {
        // 1.普通对象
        const info1 = { name: "chen" };
        const readonlyInfo1 = readonly(info1);
    
        // 2.响应式对象, 给子组件传
        // 注:给子组件传过去的,应该是一个响应式对象
        const info2 = reactive({
          name: "chenheo",
        });
        const readonlyInfo2 = readonly(info2);
    
        const updateState = () => {
          // 无法修改
          readonlyInfo1.name = "chen1";
          // 下面的是可以i修改的
          info1.name = "chen";
    
          //无法修改
          readonlyInfo2.name = "chen2";
        };
    
        return {
          updateState,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    7、Reactive判断的api

    在这里插入图片描述

    8、toRefs/toRef

    注: toRefs/toRef传入的必须是响应式的对象

    在这里插入图片描述
    在这里插入图片描述

    <template>
      <div id="app">
        <h2>{{ name }}-{{ age }}</h2>
        <button @click="changeAge">修改age</button>
      </div>
    </template>
    
    <script type="text/javascript">
    import { reactive, toRefs, toRef } from "vue";
    
    export default {
      setup() {
        // 响应式的
        const info = reactive({ name: "chen", age: 12 });
    
        // 我们从info中直接解构出来,只是赋值而已,不是响应式的
        // let { name, age } = info;
    
        // 我们希望解构出来的name,age还是响应式的, 会创建两个ref对对象,相当于 ref(name) 跟 ref(age)
        // 1.toRefs:将reactive对象中的所有属性都转成ref,建立连接, 相当于引用的同一个地方
        let { name, age } = toRefs(info);
    
        // 2.toRef: 对其中一个属性进行转换ref,建立连接
        let { name1 } = info;
        let age1 = toRef(info, "age"); //不需要再进行解构操作
    
        const changeAge = () => {
          // 有改,但是不是响应式的
          // age++;
    
          age1.value++;
          console.log("age", age.value);
          console.log(name1);
    
          //这个时候,我们改变info里面的age,也是会发生改变的
          // info.age++;
        };
    
        return {
          info,
          changeAge,
          age,
          name,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    9、ref的补充

    在这里插入图片描述

    10、自定义ref的过程

    在这里插入图片描述
    自定义ref实现双向绑定数据防抖:
    useDebounceRef.js:

    import { customRef } from "vue";
    
    // 自定义ref
    export default function (value, delay = 300) {
      let timer = null;
      // customRef要去传入的是一个函数
      // track:什么时候收集依赖; trigger:什么时候触发依赖进行更新
      return customRef((track, trigger) => {
        return {
          get() {
            track();
            return value;
          },
          set(newValue) {
            clearTimeout(timer);
            timer = setTimeout(() => {
              value = newValue;
              trigger();
            }, delay);
          },
        };
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    <template>
      <div>
        <input v-model="message" />
        <h2>{{ message }}</h2>
      </div>
    </template>
    
    <script>
    import debounceRef from "./hook/useDebounceRef";
    
    export default {
      setup() {
        const message = debounceRef("Hello World");
    
        return {
          message,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    11、computed

    在这里插入图片描述

    <template>
      <div id="app">
        <h2>{{ firstName }}- {{ lastName }}</h2>
        <h2>{{ fullName }}</h2>
        <button @click="changeName">修改名字</button>
      </div>
    </template>
    
    <script type="text/javascript">
    import { ref, computed } from "vue";
    
    export default {
      setup() {
        const firstName = ref("尘");
        const lastName = ref("浮生");
        // 这么写的化fullName不是响应式的;我们需要写成computed,才是响应式的
        // const fullName = firstName.value + " " + lastName.value;
    
        // 1.computed用法一:传入一个getter函数
        // computed的返回值是一个ref对象
        // const fullName = computed(() => firstName.value + lastName.value);
    
        // 2.computed用法二:传入一个对象,对象包含getter/setter
        const fullName = computed({
          get: () => firstName.value + lastName.value,
          set(newValue) {
            const name = newValue.split(" ");
            firstName.value = name[0];
            lastName.value = name[1];
          },
        });
        const changeName = () => {
          // firstName.value = "流";
          fullName.value = "coder chen";
        };
    
        return {
          firstName,
          lastName,
          fullName,
          changeName,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    12、watchEffect

    在这里插入图片描述

    <template>
      <div id="app">
        <h2>{{ name }}-{{ age }}</h2>
        <button @click="changeName">修改name</button>
        <button @click="changeAge">修改age</button>
      </div>
    </template>
    
    <script type="text/javascript">
    import { watchEffect, ref } from "vue";
    /**
     * Options api中,我们可以通过watch选项来侦听data 或者 props的数据变化
     * Component Api中,有两个选择: 1.使用watchEffect, 2.使用watch
     */
    export default {
      setup() {
        // watchEffect: 会自动收集响应式的依赖
        const name = ref("chen");
        const age = ref(13);
    
        const changeName = () => (name.value = "liu");
        const changeAge = () => age.value++;
    
        // 回调函数默认执行一次,立即执行一次, name
        watchEffect(() => {
          // watchEffect可以自动收集可响应式的依赖
          // 点击按钮的时候,name有执行, age没有执行,因为age没被收集过依赖
          // console.log("name:====", name.value);
    
          console.log("name:====", name.value, "age: ", age.value);
        });
    
        return {
          name,
          age,
          changeName,
          changeAge,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    13、watchEffect 停止侦听 和 清除副作用

    在这里插入图片描述
    在这里插入图片描述

    <template>
      <div id="app">
        <h2>{{ name }}-{{ age }}</h2>
        <button @click="changeName">修改name</button>
        <button @click="changeAge">修改age</button>
      </div>
    </template>
    
    <script type="text/javascript">
    import { watchEffect, ref } from "vue";
    
    export default {
      setup() {
        const name = ref("chen");
        const age = ref(13);
    
        const stop = watchEffect((onInvalidate) => {
          const timer = setTimeout(() => {
            console.log("网络请求成功");
          }, 2000);
          // 根据name和age两个变量发送网络请求, 上一次请求产生的过程,称之为副作用
          // 就是比如在修改age的时候,onInvalidate()函数会优先被调用了一下, 可以做一些相关的清除操作
          onInvalidate(() => {
            //在这个函数中, 清除额外的副作用
            // request.cancel();//取消请求
            clearTimeout(timer);
            console.log("onInvalidate");
          });
    
          console.log("name:====", name.value, "age: ", age.value);
        });
    
        const changeName = () => (name.value = "liu");
        const changeAge = () => {
          age.value++;
          if (age.value > 25) {
            // 停止侦听
            stop();
          }
        };
    
        return {
          name,
          age,
          changeName,
          changeAge,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在这里插入图片描述

    14、setup中使用ref

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    <template>
      <div id="app">
        <h2 ref="title">哈哈哈哈</h2>
      </div>
    </template>
    
    <script type="text/javascript">
    import { watchEffect, ref } from "vue";
    
    export default {
      setup() {
        // 怎么拿到title元素, 使用ref(null)返回即可,到时title会被自动赋值, 挂载之后会自动赋值到title中
        const title = ref(null);
    
        // 两种方式,可以去生命周期查看,也可以使用watchEffect
        watchEffect(
          () => {
            // 第一次立即执行,肯定是空的;第二次有具体的值
            console.log(title.value);
          },
          // 下面的对象,第一次就能打印正确的内容
          {
            // DOM更新完之后执行, 这个是要使用到DOM里面的东西才用到、
            // flush:'pre', DOM还没挂载完; post:DOM挂载完
            flush: "post",
          }
        );
    
        return {
          title,
        };
      },
      // methods:{
      //   foo(){
      //     // 以前我们时这么拿h2标签的
      //     this.$refs.title
      //   }
      // }
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    在这里插入图片描述

    15、watch在这里插入图片描述

    注: watchEffect拿不到前后变化的值;不需要指定监听谁;watch需要指定监听的是谁。

    在这里插入图片描述

    在这里插入图片描述

    侦听多个数据源代码:

    <template>
      <div id="app">
        <h2>哈哈哈哈</h2>
        <h2>{{ name }}</h2>
        <button @click="changeData">修改数据</button>
      </div>
    </template>
    
    <script type="text/javascript">
    import { ref, watch, reactive } from "vue";
    
    export default {
      setup() {
        // 1.定义可响应式对象
        const info = reactive({ name: "chen", age: 13 });
        const name = ref("chen");
    
        // 2.侦听器watch, 侦听多个,写成数组
        watch(
          [() => ({ ...info }), name],
          ([newInfo, newName], [oldInfo, oldName]) => {
            console.log(newInfo, newName, oldInfo, oldName);
          }
        );
    
        const changeData = () => {
          info.name = "hello";
        };
    
        return {
          info,
          changeData,
        };
      },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在这里插入图片描述
    在这里插入图片描述

    16、生命周期钩子函数

    注: vue3没有了create()、beforeCreate(),我们可以直接放到setup中, setup比create()/beforeCreate还要早

    在这里插入图片描述

    17、Provide/inject

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    18、案例:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    三、render函数、jsx

    在这里插入图片描述
    在这里插入图片描述

    1、render - setup方式实现计算器

    // 一旦写render函数,template就不需要了
    
    <script type="text/javascript">
    import { h, ref } from "vue";
    
    export default {
      // counter可以有两种写法: 在data中定义,也可以在setup中定义; setup是可以替代data的,也可以替代render
      setup() {
        const counter = ref(0);
    
        // return {
        //   counter,
        // };
    
        return () => {
          // h2函数的执行可以返回一个vnode
          // setup可以替换掉data, 也是可以替代render函数的
          return h("div", { class: "app" }, [
            h("h2", null, `当前计数: ${counter.value}`), //这里不需要使用this
            h(
              "button",
              {
                onClick: () => counter.value++,
              },
              "+1"
            ),
            h(
              "button",
              {
                onClick: () => counter.value++,
              },
              "-1"
            ),
          ]);
        };
      },
    
      // render() {
      //   return h("div", { class: "app" }, [
      //     h("h2", null, `当前计数: ${this.counter}`), //这里可以使用this, render函数是有绑定this的
      //     h(
      //       "button",
      //       {
      //         onClick: () => this.counter++,
      //       },
      //       "+1"
      //     ),
      //     h(
      //       "button",
      //       {
      //         onClick: () => this.counter++,
      //       },
      //       "-1"
      //     ),
      //   ]);
      // },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    2、jsx

    在这里插入图片描述

    3、自定义指令

    在这里插入图片描述
    自定义局部指令:

    <template>
      <div id="app">
        <!-- 当我们对DOM进行底层操作的时候,就会使用自定义指令 -->
        <input type="text" v-focus />
      </div>
    </template>
    
    <script type="text/javascript">
    // import { ref, onMounted } from "vue";
    
    export default {
      // 定义局部指令,可以自定义多个指令
      // directives: {
      //   focus: {
      //     // 定义指令的很多生命周期,总共有四个参数,el, bindings, vnode, preVnode
      //     mounted(el) {
      //       console.log("focus mounted");
      //       el.focus();
      //     },
      //   },
      // },
    };
    </script>
    
    <style scoped></style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    4、Teleport

    在这里插入图片描述

    5、插件

    在这里插入图片描述

  • 相关阅读:
    OT-IT融合的纽带:解读边缘计算在钢铁行业应用场景
    【LeetCode-中等题】59. 螺旋矩阵 II
    什么是杜邦分析?杜邦分析法的公式及示例
    python3多进程和多线程使用场景如何区分
    nginx使用详解
    「学习笔记」树链剖分
    Git 原理备忘录
    Dubbo-Adaptive实现原理
    Windows下的RabbitMQ安装教程(遇到很多无语的问题,已解决)
    使用Winform开发自定义用户控件,以及实现相关自定义事件的处理
  • 原文地址:https://blog.csdn.net/Anna_Liqi/article/details/125508406