Vue.js 从零开始:props 元件的沟通

上篇component元件有说到每个元件范围都应该是独立的,更不应该发生子元件直接改变根元件的情况,元件与元件又该怎麽正确传递资料呢?


Props起手式

子元件做好之後,为了能重复使用,就会使用外部元件的资料,供传子元件使用,但是又不能靠子元件直接取用,这时就用使用props属性来完成。

<div id="app">
    <h4>{{ text }}</h4>
    <con-tainer :test-props="demo"></con-tainer>   
</div>

:test-props="demo",前面的:test-props内层元件,後面的"demo"外层元件,好记的方式:前内後外。

const app = Vue.createApp({
  data() {
    return {
      text: "外部元件",
      demo: "外部元件传递的文字"
    };
  }
});
app.component("ConTainer", {
  props: ["testProps"],
  template: `<div>
    <h4>{{ text }}</h4><h3>{{ testProps }}<h3>
  </div>`
});
app.mount("#app");

内部元件的props属性宣告从外部引入到内部元件,并且透过外层模板的v-bind完成两个元件的资料传递,HTML可以说是两个元件沟通的桥梁。

补充:``props命名有使用驼峰命名,记得写在模板时要改为连字号,因为HTML不分大小写,例如:props: ["testProps"]testProps要改为test-props


props单向数据流

当内层元件想使用v-model来改变外层元件的资料时会跳出这行警告,[Vue warn]: Attempting to mutate prop "test". Props are readonly.Props是有读取限制的。

<div id="app">
    <con-tainer :test-props="demo"></con-tainer>   
</div>
const app = Vue.createApp({
  data() {
    return {
      demo: "外部元件传递的文字"
    };
  }
});
app.component("ConTainer", {
  props: ["testProps"],
  template: `<div>
    <h3>{{ testProps }}<h3>
    <input type="text" v-model="testProps">
  </div>`
});
app.mount("#app");


传入props时有v-bind与没有v-bind的区别

观察import-num有无绑定v-bind的差别:

<div id="app">
    <con-tainer import-num="400"></con-tainer>
    <con-tainer :import-num="num"></con-tainer>   
</div>
const app = Vue.createApp({
  data() {
    return {
      num: 500
    };
  }
});
app.component("ConTainer", {
  props: ["importNum"],
  template: `<div>
    <h3>value: {{ importNum }} </h3>
    <h3>value: {{ typeof importNum }} </h3>
  </div>`
});
app.mount("#app");

在外部元件的模板里,未绑定v-bind的情况下,内部元件props依然可以接受资料,任何值传入到内部元件props都会是string的型别。有绑定v-bind就会依据外部元件datanum型别,内部也会显示该型别。


props型别验证

多人开发有时会需要验证外部元件props传入的型别,这时就可以使用型别验证的技巧,来得知适当的提示。

上面范例在内元件中props都是使用阵列方式(可以带多个值),例如props:['one','two'],如果要进行验证,就要改为大括号物件的形式。

准备好一个内部元件areaComponentconsole.log还不会跳出提示:

<div id="app">
    <area-component
     :pro-a="fun" :pro-b="text"
      pro-c="num" :pro-d="num">
    </area-component>
</div>
const areaComponent = {
  props: {
    proA: Function,
    //多个型别检查
    proB: [String, Number],
    //必要值 物件形式可以设立多个条件
    proC: {
      type: String,
      required: true
    },
    //预设值
    proD: {
      type: Number,
      default: "hello"
    }
  },
  template: `{{ proA }} <br> {{ proB }} <br> {{ proC }} <br> {{ proD }}`
};
const app = Vue.createApp({
  data() {
    return {
      num: 500,
      text: "小明",
      boo: true,
      fun: () => {
        return "a";
      },
      test: 100
    };
  },
  components: {
    areaComponent
  }
});
app.mount("#app");



将上面范例程序码内部元件:pro-a="fun"fun改为text

<div id="app">
    <area-component :pro-a="text" :pro-b="text" pro-c="num" :pro-d="num"></area-component>
</div>

此时console.log就会跳出提示:[Vue warn]: Invalid prop: type check failed for prop 'proA'. Expected Function, got String with value '小明'.

意思是预期应该是一个Function,但传入结果却是字串

补充

required: true:一定要给一个值,如果没有就会跳出提示。
default: "hello":当没有透过props传入值,画面就会给出hello的预设值,可以将:pro-d="num"移除看出差异在哪里。
pro-c="num"console.log为什麽没跳出提示?因为没绑定v-bind,都会自动变成String型别。

codePen 完整范例

以上如有错误,欢迎指教

/images/emoticon/emoticon22.gif


参考资料

六角学院
重新认识 Vue.js
Vue.js


<<:  给自己多一些鸡汤,补一下能判断的脑袋

>>:  【Day19】维持连线 ─ 工具实作篇(一)

【Day29】Pixi-AnimatedSprite

PIXI.AnimatedSprite 今天介绍用PIXI.AnimatedSprite做影格动画 ...

[DAY 17]Discord server串接webhook

最近有打算写一个功能 FF14官网有新消息发布,bot就会把消息发送到discord主频上 但後来发...

Day18-React Router 篇-上篇

此篇章不会从头开始介绍 React Router,而是挑选一些它的功能去做介绍,因此本篇的范例皆是从...

故事的例子

先说明:今天加班到现在,所以先写一点点,後续再补上。 前天的文章有一位读者提问: 如果将团队在组织中...

Day14 Lab 2 - Object storage data层和心跳

Data层的任务主要是储存Object的component,保证资料的安全,他和API层一样也有AP...