整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

React核心属性props属性及用法详解

React核心属性props属性及用法详解

件核心属性-props

需求:自定义用来显示一个人员信息的组件

javascript复制代码   class Person extends React.Component {
            render() {
                const { name, age, sex }=this.props;
                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>年龄:{age + 1}</li>
                        <li>性别:{sex}</li>
                    </ul>
                )
            }
        }


        ReactDOM.render(<Person name="jerry" age={19} sex="男" dance={dance} />, document.getElementById('test1'))
        ReactDOM.render(<Person name="Lilly" age={18} sex="女" />, document.getElementById('test2'))
        ReactDOM.render(<Person name="双下巴" age={23} sex="不明" />, document.getElementById('test3'))
  1. 姓名必须指定,且为字符串类型
go复制代码           //对标签属性进行类型、必要性的限制
        Person.propTypes={
            name: PropTypes.string.isRequired,
            sex: PropTypes.string,
            age: PropTypes.number,
            dance: PropTypes.func
        }

. 性别为字符串类型,如果性别没有指定,默认为男 Person.defaultProps={ sex: '未知', age: 18 } 3. 年龄为数字类型,必须指定 4. 给某个组件添加dance函数,限制dance只能是函数类型

javascript复制代码ReactDOM.render(<Person name="jerry" age={19} sex="男" dance={dance} />, document.getElementById('test1'))

function dance() {
    console.log(' be good at dancing')
}

Person.propTypes={
    dance: PropTypes.func
}

在函数的render函数中打印console.log(this),可以查看渲染数据的结果

props的性质和作用

  1. 每个组件对象都会有props属性
  2. 组件标签的所有属性都保存在props中
  3. 通过标签属性从组件外向组件内传递变化的数据。
  4. 注意:组件内部不要修改props的值

注意可以运算不可以修改。运算和修改的区别如图所示

用法

内部读取某个属性值this.props.name

在render函数里面

arduino
复制代码console.log(this.props.name)

对props中的属性值进行类型限制和必要性限制

  1. 第一种方式(React v15.5开始已弃用) Person.propTypes={ name: React.PropTypes.string.isRequired, sex: PropTypes.string, age: PropTypes.number } 若一直在React身上加PropTypes属性,那么React核心对象会很大。
  2. 使用 prop-types库对标签属性进行限制,React代码打包之后会更小一些
  3. ini复制代码 <script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
    <script type="text/babel">
    Person.propTypes = {
    name:PropTypes.string.isRequired,
    sex: PropTypes.string,
    age: PropTypes.number
    }
    </script>
  4. 拓展属性:将对象的所有属性通过props传递 const person3={ name: '双下巴', age: 23, sex: '不 明' } ReactDOM.render(<Person {...person3} />, document. getElementById('test3'))
  5. 默认属性值 Person.defaultProps={ 属性:值 }
  6. 类式组件类中的构造函数
kotlin复制代码  constructor(props) {
                super(props)
                this.state={ 属性:值}
                // 解决changeWeather中this指向的问题
                this.组件实例新属性名称=this.自定义函数.bind(this)
            }

props的基本形式

xml复制代码  <div id="test1"></div>
    <div id="test2"></div>
    <div id="test3"></div>
    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    <!-- 生产环境中不建议使用 -->
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
    <script type="text/babel">

        class Person extends React.Component {
            render() {
                console.log(this)
                const { name, age, sex }=this.props
                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>年龄:{age}</li>
                        <li>性别:{sex}</li>
                    </ul>
                )
            }
        }
        ReactDOM.render(<Person name="jerry" age="19" sex="男" />, document.getElementById('test1'))
        ReactDOM.render(<Person name="Lilly" age="18" sex="女" />, document.getElementById('test2'))
        ReactDOM.render(<Person name="双下巴" age="23" sex="不明" />, document.getElementById('test3'))
    </script>

运行截图

批量传递props

花括号加展开运算符接收数据

复制代码{...数组或者集合}

介绍一下展开运算符

javascript复制代码        let arr1=[1, 3, 5, 7, 9]
        let arr2=[1, 2, 3, 4]
        console.log(...arr1);//展开一个数组
        let arr3=[...arr1, ...arr2]//连接数组
        console.log('arr3:', arr3)
        function sum(...numbers) {
            return numbers.reduce((preValue, currentValue)=> {
                return preValue + currentValue
            })
        }
        console.log(sum(1, 2, 3, 4));//10
ini复制代码     let person={ name: 'tom', age: 18 }
     console.log(...person);展开运算符不能展开对象

报错信息 Uncaught TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function 展开运算符不能展开对象。

对传递的标签属性进行类型限制,必要性限制和默认设置。React15使用以下代码进行标签属性限制

ini复制代码        Person.propTypes={
            name: React.PropTypes.string
        }

React16版本及其以后不再从React身上直接取属性,因为这样可能会使得React变得臃肿。使用prop-types.js,然后

xml
复制代码<script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>

props的简写方式

如果想要把标签属性的限制和默认值相关代码放在组件类的内部,可以尝试下面的写法(写在组件里面,和render函数是并列关系)

yaml复制代码static propTypes={
    name: PropTypes.string.isRequired,
    sex: PropTypes.string,
    age: PropTypes.number,
    dance: PropTypes.func
};
static defaultProps={   
    sex: '未知',
    age: 18
}

测试这段代码是否可行,可以将渲染组件到页面的代码去掉性别,dance直接赋值,如果生效会显示关于属性限制的相关的报错

类式组件中的构造器与props

通常在React中,构造函数仅用于以下两种情况

通过给this.state赋值对象来初始化内部state

为事件处理函数绑定实例

构造器是否接收props,是否传递给super取决于是否希望在构造器上通过this访问props

undefined打印了三次是因为页面中有三次渲染

函数式组件使用props

最新的React建议使用函数式组件而不是类式组件。 this.state.x,this.props.name中的this是组件实例对象,函数式组件中没有this,不能state,refs,但是可以props

xml复制代码    <script type="text/babel">

        function Predecessor() {
            const { name, age, address }=props
            return (
                <ul>
                    <li>name:{name}</li>
                    <li>age:{age}</li>
                    <li>address:{address}</li>
                </ul>
            )
        }
        ReactDOM.render(<Predecessor name='LS' age='18' address='Mars' />, document.getElementById('demo1'))
    </script>

props未定义的原因是没有在函数的参数里接收props

上面代码中从函数参数中读取属性也可以写解构的形式

css复制代码 function Predecessor({ name, age, address }) {
            return (
                <ul>
                    <li>name:{name}</li>
                    <li>age:{age}</li>
                    <li>address:{address}</li>
                </ul>
            )
        }

代码的解构和从函数参数中读取属性是等价的。注意不要忘记花括号,因为属性的集合是一个对象。

对函数式组件属性的限制写在function外部。

最新版的React建议使用函数式组件,所以函数式组件使用props值得关注。

果你一直在阅读有关"props"内容,你会发现我们可能也一直在使用它们(即使没有意识到),但也许你并不完全确定它们是什么。或者如何正确使用它们,并充分利用它们。

当你读完这篇指南时,你就会知道成为一名高效的Vue开发者所需要知道的关于props的一切。

在本指南中,我们将介绍关于 props 的最重要的事情:

  • 什么是 props ?
  • props 的两个主要特点
  • 如何将 props 传递给其他组件
  • 添加 props 类型
  • 添加必填的 props
  • 设置默认值

什么是 props ?

props 是我们在不同组件之间传递变量和其他信息的方式。这类似于在 JS 中,我们可以将变量作为参数传递给函数:

这里,我们将变量myMessage作为参数message传递给函数。在函数内部,我们可以将该值作为message访问。

props的工作原理与此非常相似。我们将props传递给另一个组件,然后该组件可以使用该值。但是首先需要了解一些规则。

props 的两个主要特点

在处理props时,有两件事需要特别注意:

  1. props 通过组件树传递给后代(而不是向上传递)
  2. props 是只读的,不能修改

Vue 使用单向数据流,这意味着数据只能从父组件流向子组件,不能将数据从子对象传递到父对象。因为父组件“拥有”它传递的值,所以子组件不能修改它。如果只允许一个组件更改它,那么跟踪bug就更容易了,因为我们确切地知道应该从哪里查找。

在开发确保没有违反这两条规则,开发就会变得更容易些,出问题也比较好找原因。接着来看看如何将 props 从一个组件传递到另一个组件。

将 props 传递给其他组件

如果希望将值从组件传递到子组件,这与添加HTML属性完全相同。

<template>
  <Camera
    name="Sony A7RIV"
    img="../sony-a7riv.jpg"
  />
</template>

Camera组件将使用name和img props 来渲染自身页面。内容大概如下:

<template>
  <div class="camera">
    <h2 class="camera__name">{{ name }}</h2>
    <img class="camera__image" :src="img" />
  </div>
</template>

在这里,我们将name渲染到h2标记中,并使用img设置img标记上的src属性。

但是,如果我们将此信息存储在某个位置的变量中怎么办?

为此,我们需要使用稍微不同的语法,因为我们希望使用 JS 表达式而不是传递字符串。

<template>
  <Camera
    v-bind:name="cameraName"
    v-bind:img="cameraImage"
  />
</template>

v-bind:name="cameraName"行告诉Vue将 JS 表达式cameraName绑定到 propname。JS 表达式是 JS 的任何代码段。可能是像我们在此处这样的变量名,或更复杂的名称。

还可以使用逻辑或 img 设置图像路径:

<template>
  <Camera
    v-bind:name="cameraName"
    v-bind:img="cameraImage || '../no-camera-found.jpg'"
  />
</template>

v-bind 可以用简写形式 :

<template>
  <Camera
    :name="cameraName"
    :img="cameraImage || '../no-camera-found.jpg'"
  />
</template>

添加 props

在此代码实际起作用之前,我们需要获取Camera组件才能实际收听props。默认情况下,组件会忽略它们。为此,我们必须在组件定义中添加一个props部分:

export default {
  name: 'Camera',
  props: ['name', 'img'],
}

通常不建议这么写,应该为props对象指定类型:

export default {
  name: 'Camera',
  props: {
      name: {
      type: String,
      },
      img: {
      type: String,
      }
  }
}

通过从数组到对象,我们可以指定更多的 props 细节,比如类型。我们为什么要向props 添加类型?

在Vue中,props 可以有很多不同的类型:

  • String
  • Number
  • Boolean (true 或者 false)
  • Array
  • Object

通过添加类型,我们可以设置我们期望收到的数据类型。如果我们将camera的props中的name设置为true,它将无法正常工作,因此Vue会警告我们使用错误。

接着添加一个rating到我们的Camera组件中,该 rating 类型为 Number:

export default {
  name: 'Camera',
  props: {
      name: {
      type: String,
      },
      img: {
      type: String,
      },
      rating: {
      type: Number,
      },
  }
}

然后在 template 中显示 rating:

<template>
  <div class="camera">
    <h2 class="camera__name">{{ name }}</h2>
    <span class="camera__rating">{{ rating }}</span>
    <img class="camera__image" src="img" />
  </div>
</template>

在外层调用:

<template>
  <Camera
    name="Sony A7RIV"
    img="../sony-a7riv.jpg"
    :rating="9"
  />
</template>

必填的 props

不是所有的 props 都是一样的,为了使组件正常工作,其中一些要求必填的。

对于我们的Camera组件,我们肯定需要一个name,但 img 和 rating 不是必需的。

export default {
  name: 'Camera',
  props: {
      name: {
      type: String,
      required: true,
      },
      img: {
      type: String,
      },
      rating: {
      type: Number,
      },
  }
}

通过设置 required: true 要求我们的 name 是必需要传入的,相反,required 为false 对应的props可传可不传。

默认值

对于不是每次都传入的 props,我们可以为其,添加默认值。

export default {
  name: 'Camera',
  props: {
      name: {
      type: String,
      required: true,
      },
      img: {
      type: String,
      default: '../no-camerage-found.jpg',
      },
      rating: {
      type: Number,
      },
  }
}

前面我们通过逻辑或为img添加默认值,这次我们使用 default 属性为img设置默认值。

同样也需要为我们的rating设置默认值。如果没有设置也没有从外部传入,我们访问的时候就会得到undefined,这可能会给我们带来一些问题

在模板外使用 props

虽然能够在template中使用props很棒,但是真正强大的功能来自于在方法、计算属性和组件中在使用其他 JS 中使用它们。

在我们的template中,我们看到我们只需要props名称,例如:{{rating}}。但是,在Vue组件的其他任何地方,我们都需要使用this.rating访问我们的props。

让我们重构应用程序,以便为图像使用标准的URL结构。这样,我们不必每次都将其传递给Camera组件,而只需从名称中找出即可。

我们将使用以下结构:./images/cameras/${cameraName}.jpg

因此,如果 camera 是Sony A6400,则URL将变为./images/cameras/Sony%20A6400.jpg。%20来自对空格字符的编码,因此我们可以在URL中使用它。

首先,我们将移除不再需要的img props

export default {
  name: 'Camera',
  props: {
      name: {
      type: String,
      required: true,
      },
      rating: {
      type: Number,
      default: 0,
      },
  }
}

然后,我们将添加一个计算属性,该属性将为我们生成图像URL:

并非所有字符都可以在URL中使用,因此encodeURIComponent会为我们转换这些字符。

因为我们可以使用与常规props相同的方式来访问此计算 props,所以我们根本不需要更改模板,并且模板可以像以前一样保持不变:

<template>
  <div class="camera">
    <h2 class="camera__name">{{ name }}</h2>
    <span class="camera__rating">{{ rating }}</span>
    <img class="camera__image" src="img" />
  </div>
</template>

样,您可以在以下位置使用组件的props:

  • watch 中
  • 生命周期 hook
  • method
  • computed 中

以及组件定义中的其他任何地方!

总结

以上,这些是关于 props 的知识点,但是,总会有更多东西要学习。Vue 也是一个永无止境的学习过程。keep going !


作者:Michael Thiessen 译者:前端小智 来源:Michael原文:https://reactgo.com/vuejs-props-tutorial/

.传递数据

1.props 传入单数据

就像 data 一样,prop 可以用在模板内,同样也可以在 vm 实例中像“this.message”这样使用

  1. <template>
  2. <div id="app">
  3. <h1>{{title}}</h1>
  4. <child message="hello! Prop"></child>
  5. </div>
  6. </template>
  7. <script>
  8. import Vue from 'vue';
  9. Vue.component('child', {
  10. // 声明 props
  11. props: ['message'],
  12. template: '<span>{{ message }}</span>'
  13. })
  14. export default {
  15. name: 'app',
  16. data: function () {
  17. return {
  18. title: '使用 Prop 传递数据'
  19. }
  20. }
  21. }
  22. </script>

<child message="hello! Prop"></child>

2.props 传入多个数据

如果在父组件的模板类添加其他元素或者字符会有:

①在最前面加入—每个子组件渲染出来都会在其前面加上

②在最后面加入—每个子组件渲染出来都会在其后面加上

③在中间加入—他前面子组件后面加上,后面的子组件后面加上

(1)1种

<template>

<div id="app">

<child msg="hello!"></child>

<child nihao="hello1!"></child>

<child nisha="hello2!"></child>

</div>

</template>

<script>

import Vue from 'vue';

Vue.component('child', {

props: ['msg','nihao','nisha'],

template: '<span>{{ msg }}{{nihao}}{{nisha}}</span>',

});

export default {

name: 'app',

data: function () {

return {

}

}

}

</script>

(2)2种

template: '<span>小明,{{ msg }}{{nihao}}{{nisha}}</span>',

(3)3种

template: '<span>{{ msg }}{{nihao}}{{nisha}}小明</span>',

(4)4种

template: '<p>{{ msg }}小明 {{nihao}} {{nisha}}小林</p>',

注意:camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名:

Vue.component('child', {

// camelCase in JavaScript

props: ['myMessage'],

template: '<span>{{ myMessage }}</span>'

})

<!-- kebab-case in HTML -->

<child my-message="hello!"></child>

二.动态prop

要动态地绑定父组件的数据到子模板的 props,与绑定到任何普通的HTML特性相类似,就是用 v-bind。每当父组件的数据变化时,该变化也会传导给子组件

<template>

<div id="app">

<input v-model="parentMsg">

<br>

<child v-bind:my-message="parentMsg"></child>

</div>

</template>

<script>

import Vue from 'vue';

export default {

name: 'app',

data: function () {

return {

title: '使用 Prop 传递数据',

parentMsg: 'Message from parent'

}

},

components: {

child: {

props: ['myMessage'],

template: '<span>{{myMessage}}</span>'

}

}

}

</script>

三.表达式计算,传递值

如果想传递一个实际的 number,需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算

<comp v-bind:some-prop="1"></comp>

<template>

<div id="app">

<p>{{tle1}}:<comp total="123+456"></comp></p>

<p>{{tle2}}<comp :total="123+456"></comp></p>

</div>

</template>

<script>

import Vue from 'vue';

Vue.component("comp", {

props: ["total"],

template: "<span>total: {{total}}</span>",

});

export default {

name: 'app',

data: function () {

return {

tle1: '这里传递是字符串',

tle2: '用了v-bind动态语法,传递值会通过js的表达式计算,得到个值:'

}

}

}

</script>

四.Prop类型绑定

prop 默认是单向绑定:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。

五.prop验证

传入的数据不符合规格,Vue 会发出警告。当组件给其他人使用时,这很有用。

<template>

<div id="app">

<div>name:{{dr.name}}, age:{{dr.age}}.<input v-model="telphone" /> </div>

<br /><br />

<div>

<span>vue自定义组件</span><br />

<child :msg_null="123+456" msg_string="adss"

:msg_number="0" :msg_twoway.sync="telphone"

:msg_validate="mobilephone"

:msg_number2String="mobilephone"

:msg_obj2json="dr"

:msg_json2obj="drJson"></child>

</div>

</div>

</template>

<script>

import Vue from 'vue';

Vue.component("child", {

props: {

msg_null: null,//基础类型检测("null"意思是任何类型都可以)

msg_string: { //String类型,必须是定义过的,可以是空字符串""

type: String,

required: true,

},

msg_number: {//Number类型,默认值100

type: Number,

default: 100,

},

msg_obj: {//Object类型,返回值必须是js对象

type: Object,

default: function() {

return {

name: "DarkRanger",

age: "18",

}

}

},

msg_twoway: { //指定这个prop为双向绑定,如果绑定类型不对将抛出一条警告

type: String,

twoWay: true,

},

msg_validate: { //自定义验证,必须是Number类型,验证规则:大于0

type: Number,

validator: function(val) {

return val > 0;

}

},

msg_number2string: { //将值转为String类型,在设置值之前转换值(1.0.12+)

coerce: function(val) {

return val + ""

}

},

msg_obj2json: { //js对象转JSON字符串

coerce: function(obj) {

return JSON.stringify(obj);

}

},

msg_json2obj: {//JSON转js对象

coerce: function(val) {

return JSON.parse(val);

}

},

},

template: '<div><b>msg_null=123+456=</b> {{msg_null}}</br>

</br><b>msg_string="1":</b>{{msg_string}}</br></br><b>msg_number:</b> {{msg_number}}</br>

</br><b>msg_obj:</b>{{"name-->"+msg_obj.name+", age-->"+msg_obj.age}}</br>

</br><b>msg_twoway:</b><input v-model="msg_twoway"></br></br><b>msg_validate:</b>{{msg_validate}}</br>

</br><b>msg_number2String:</b> {{msg_number2string}}</br></br><b>msg_obj2json:</b> {{msg_obj2json}}</br>

</br><b>msg_json2obj:</b>{{"name: "+msg_json2obj.name+"; age: "+msg_json2obj.age}}</div>'

});

export default {

name: 'app',

data: function () {

return {

telphone: "0356-1234567",

mobilephone: 15912345678,

dr: {

name: "DarkRanger",

age: 25

},

drJson: {"name":"DarkRanger","age":25}

}

}

}

</script>

解释:

①、msg_null:不论什么数据类型,只要能解析成功,就渲染成正确的html

②、msg_string:只能传递String类型的字符串,如果将child06中的“msg_string="this is string"”更改为“:msg_string="1+2"”,

控制台报错:

③、msg_number:如果在child06标签中没有定义值,我们将会取默认值100,现在定义了“:msg_number="99"”,如果将“:msg_number="99"”更改为“msg_number="99"”,控制台报错:

④、msg_obj:在js中我们定义的msg_obj的default属性是一个具有返回js对象的函数,这里取值的时候直接取的就是返回值,如果在child06中定义或者绑定了新的js对象,则会将msg_obj更新为新的数据。取js对象属性值的时候用{{Object.prop}}取值即可。

⑤、msg_twoway:双向数据绑定,在测试的过程中发现,即使设置“twoWay: true”,当子组件发生变化时,vue实例的数据并不会更新,还是单向的数据绑定,这里我将child06中原先的“:msg_twoway="telphone"”更改为“:msg_twoway.sync="telphone"”,保证测试能够数据双向绑定。

⑥、msg_validate:有验证规则的组件数据,这里定义的规则是当前数值必须大于0,如果将child06中的“:msg_validate="mobilephone"”更改为“:msg_validate="-1"”。控制台报错:

⑦、msg_number2string:在结果赋值之前将数值转化为字符串。

⑧、msg_obj2json:vue.js内置了JSON的两个方法,一个是JSON.parse(jsonStr)--》将JSON字符串转化为js对象,另外一个是JSON.stringify(obj)--》将js对象序列化为JSON字符串。

这里是将obj转化为json字符串,需要添加coerce属性,它是一个具有返回json字符串的函数,当然不是必须得用JSON.stringify(obj)方法,只要方法合理,能够转化为json能够识别的字符串即可。

⑨、msg_json2obj: 将json字符串转化为js对象。