Vue - day03

22 阅读1分钟

一、props参数验证

约束组件调用者所传递的 props 参数的数据类型,props 是单向数据流,不能在组件内部尝试修改 props 传递props的细节

props: {
    name: {
      type: String,
    },
    score: {
      type: Number,
      required: true, //要求必传
    },
    hobby: {
      type: String,
      default: "唱跳",//默认
    },
    status: {
      type: String,
      validator(value) {
        //value就是用户传入的status
        // 优秀、及格、不及格

        return ["优秀", "及格", "不及格"].includes(value); //return结果为true,代表验证通过
      },
    },
},

二、$emit子父通信

$emit

2.1 子组件绑定事件

<h3>这是子组件,银行卡余额:{{money}}</h3>
<button @click="handleChild">问候</button>

2.2 子组件在事件函数中通过this.$emit自定义事件

methods: {
    handleChild() {
      // 触发父级自定义事件give-me-money
      this.$emit("give-me-money", {
        msg: "最近天气比较热,注意避暑,顺便打点钱",
        n: 10000,
      });
      this.money += 10000;
    },
  },

2.3 父级在调用子组件的时候,需要绑定对应的子组件定义的事件

<h1>父级空间,银行卡余额:{{money}}</h1>
<my-child @give-me-money="handleFather"></my-child>

2.4 父级在事件函数中可以得到子组件传递的参数,进行后续操作

methods: {
    handleFather(obj) {
      // console.log(obj);
      let { msg, n } = obj; //解构赋值
      console.log(msg);
      this.money -= n;
    },
  },
<div id="app">
      <h1>父级空间,银行卡余额:{{money}}</h1>
      <my-child @give-me-money="handleFather"></my-child>
</div>
<script>
    let app = Vue.createApp({
      //创建vue应用
      data() {
        //数据包
        return {
          money: 1000000000,
        };
      },
      methods: {
        handleFather(obj) {
          // console.log(obj);
          let { msg, n } = obj; //解构赋值
          console.log(msg);
          this.money -= n;
        },
      },
    });
    app.component("my-child", {
      template: `<div>
          <h3>这是子组件,银行卡余额:{{money}}</h3>
          <button @click="handleChild">问候</button>
        </div>`,
      data() {
        return {
          money: 10,
        };
      },
      methods: {
        handleChild() {
          // 触发父级自定义事件
          this.$emit("give-me-money", {
            msg: "最近天气比较热,注意避暑,顺便打点钱",
            n: 10000,
          });
          this.money += 10000;
        },
      },
    });
    app.mount("#app");
</script

三、组件的v-model

参考文档 v-model本身做了两件事<my-comp :modelValue="msg" @update:modelValue="直接修改msg">

3.1 子组件通过props: ["modelValue"]接收v-model传递的数据

<my-comp v-model="msg"></my-comp>
props: ["modelValue"], //接收组件通过v-model传递的数据

3.2 子组件通过子父通信this.$emit("update:modelValue", v)将数据传递给父级

this.$emit("update:modelValue", v); //通过子父通信将组件内的值传给父级
<body>
    <div id="app">
      <h1>{{msg}}</h1>
      <!-- v-model本身做了两件事
        <my-comp :modelValue="msg" @update:modelValue="直接修改msg"></my-comp>
      -->
      <my-comp v-model="msg"></my-comp>
    </div>
</body>
<script>
    let app = Vue.createApp({
      data() {
        return {
          msg: "Hello Vue",
        };
      },
    });
    app.component("my-comp", {
      props: ["modelValue"], //接收组件通过v-model传递的数据
      template: `<div>
          演示组件中使用v-model,
          <input type="text" :value="modelValue" @input="handleInput"/>
        </div>`,
      methods: {
        handleInput(ev) {
          console.log(ev);
          let v = ev.target.value; //实时获取输入框的值
          this.$emit("update:modelValue", v); //通过子父通信将组件内的值传给父级
        },
      },
    });
    app.mount("#app");
</script>

四、插槽

让组件调用者,可以向组件内部传递 HTML 结构

4.1 匿名插槽

<div id="app">
        <my-comp>
            <p>匿名插槽</p>
        </my-comp>
</div>
<script>
    let app = Vue.createApp({
        
    })
    app.component("my-comp",{
        template:`<div>
                演示插槽
                <slot></slot>
            </div>`
    })
    app.mount("#app")
</script>

4.2 具名插槽

<div id="app">
        <my-comp>
            <template v-slot:s1>
                <h1>具名插槽1{{msg}}</h1>
            </template>
            <template #s2>
                <h1>具名插槽2{{msg2}}</h1>
            </template>
        </my-comp>
</div>
<script>
    let app = Vue.createApp({
        data() {
            return {
                msg:"父级作用域"
            }
        },

    })
    app.component("my-comp",{
        template:`<div>
                <slot name="s2"></slot>
                具名插槽
                <slot name="s1"></slot>
            </div>`,
        data() {
            return {
                msg2: "数据2"
            }
        },
    })
    app.mount("#app")
</script>

4.3 作用域插槽

在组件内插槽中向组件外传递数据,解决插槽的内容无法访问到子组件的状态问题

<div id="app">
        <!-- 方法一 -->
        <!-- <my-comp v-slot="slotProps">
            <h1>作用域插槽1,{{msg}}</h1>
            <h1>作用域插槽2,{{slotProps.count}}</h1>
        </my-comp> -->
        <!-- 方法二 解构赋值的写法 -->
        <my-comp v-slot="{count}">
            <h1>作用域插槽1,{{msg}}</h1>
            <h1>作用域插槽2,{{count}}</h1>
        </my-comp>
</div>
<script>
    let app = Vue.createApp({
        data(){
            return{
                msg:"11111"
            }
        }
    })
    app.component("my-comp",{
        data(){
            return {
                num:200
            }
        },
        template:`<div>
                作用域插槽
                <slot :count="num"></slot>
            </div>`
    })
    app.mount("#app")
</script>

五、$refs 实现组件通信

  • 获取并操作 DOM、组件对象
  • 应用场景:
    • 操作焦点
    • 多媒体操作(音频、视频)
    • 集成第三方库 (地图、图表)
<div id="app">
        <button @click="handleFn">按钮</button>
        <h1 ref="myH1">内容</h1>
        <input type="text" ref="myInput">
        <my-comp ref="myComp"></my-comp>
</div>
<script>
    let app = Vue.createApp({
        methods:{
            handleFn(){
                this.$refs.myH1.style.border="1px solid pink";
                this.$refs.myH1.style.transform="rotate(50deg)";
                this.$refs.myInput.focus();
                this.$refs.myComp.num++;
            }
        },
        mounted(){
            this.$refs.myInput.focus();
        }
    })
    app.component("my-comp",{
        data(){
            return{
                num:800
            }
        },
        template:`<div>
                {{num}}
            </div>`,
    })
    app.mount("#app")
</script>

六、单页面应用(SPA --- Single Page Application)

  • 整个项目只有一个 html 文件
  • 视觉上的页面切换,本质是组件的切换 (.vue 单文件组件)