精华内容
下载资源
问答
  • Vue props 属性原理

    千次阅读 2019-09-13 14:34:06
    父组件通过props属性向子组件传递数据,定义组件的时候可以定义一个props属性,值可以是一个字符串数组或一个对象。 例如: <!DOCTYPE html> <html lang="en"> <head> <me...

    文章转自:https://www.cnblogs.com/greatdesert/p/11090143.html

     

    父组件通过props属性向子组件传递数据,定义组件的时候可以定义一个props属性,值可以是一个字符串数组或一个对象。

    例如:

    复制代码

    <!DOCTYPE html>  
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    </head>
    <body>
        <div id="app"><child :title="message"></child></div>        
        <script>
            Vue.component('child',{
                template:'<h1>{{title}}</h1>',props:['title']       //这里props是一个字符串数组
            })
            var app = new Vue({
                el:'#app',data:{message:'Hello World'}
            })  
        </script>
    </body>
    </html>

    复制代码

    这里我们给child这个组件定义了名为title的props,父组件通过title特性传递给子组件,渲染为:

    props除了数组,也可以是一个对象,此时对象的键对应的props的名称,值又是一个对象,可以包含如下属性:

             type:        ;类型,可以设置为:String、Number、Boolean、Array、Object、Date等等             ;如果只设置type而未设置其他选项,则值可以直接用类型,例如:props:{title:Object}
            default      ;默认值
            required    ;布尔类型,表示是否必填项目
            validator    ;自定义验证函数   

    例如:

    复制代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <title>Document</title>    
    </head>
    <body>
        <div id="app"><child></child></div>        
        <script>
            Vue.component('child',{
                template:'<h1>{{title}}</h1>',props:{title:{default:'Hello World'}}                 //这里我们定义的title是个对象,含有默认值
            })
            var app = new Vue({
                el:'#app'
            })  
        </script>
    </body>
    </html>

    复制代码

    这里父组件app没有给子组件child传递数据,子组件使用了默认值Hello World,渲染的结果和第一个例子是一样的。

     

     源码分析


     以上面的例1为例,Vue.component()注册组件的时候会调用Vue.extend()生成一个Vue基础构造器,内部会调用mergeOptions函数合并属性, mergeOptions又会调用normalizeProps对props的属性进行一些规范化的修饰,如下:

    复制代码

    function normalizeProps (options, vm) {       //第1361行 规范化props属性
      var props = options.props;                        //尝试获取props属性
      if (!props) { return }
      var res = {};
      var i, val, name;
      if (Array.isArray(props)) {                       //如果props是个数组       ;这是props的数组用法的分支
        i = props.length;
        while (i--) {                                     //遍历props
          val = props[i];
          if (typeof val === 'string') {                  //如果值是一个字符串
            name = camelize(val);
            res[name] = { type: null };                       //保存到res里面                  ;例如:{ title: {type: null} }
          } else {
            warn('props must be strings when using array syntax.');
          }
        }
      } else if (isPlainObject(props)) {                //如果props是个对象         ;这是props的对象用法的分支
        for (var key in props) {
          val = props[key];
          name = camelize(key);
          res[name] = isPlainObject(val)
            ? val
            : { type: val };
        }
      } else {
        warn(
          "Invalid value for option \"props\": expected an Array or an Object, " +
          "but got " + (toRawType(props)) + ".",
          vm
        );
      }
      options.props = res;
    }

    复制代码

     经过normalizeProps规范后,props被修饰为一个对象格式,例子里的执行到这里等于:

    接下来_render函数执行遇到该组件时会执行createComponent函数,该函数又会执行extractPropsFromVNodeData(data, Ctor, tag)函数,如下:

    复制代码

    function extractPropsFromVNodeData (      //第2109行 获取原始值
      data,
      Ctor,
      tag
    ) {
      // we are only extracting raw values here.
      // validation and default values are handled in the child
      // component itself.
      var propOptions = Ctor.options.props;                  //获取组件的定义的props对象,例如:{message: {type: null}}
      if (isUndef(propOptions)) {
        return
      }
      var res = {};
      var attrs = data.attrs;                                   //获取data的attrs属性,例如:{title: "Hello Vue"}
      var props = data.props;                                   //获取data的props属性,这应该是建立父子组件时的关系
      if (isDef(attrs) || isDef(props)) {                       //如果data有定义了attrs或者props属性
        for (var key in propOptions) {                            //遍历组件的props属性
          var altKey = hyphenate(key);
          {   
            var keyInLowerCase = key.toLowerCase();                 //hyphenate:如果key是是驼峰字符串,则转换为-格式
            if (
              key !== keyInLowerCase &&
              attrs && hasOwn(attrs, keyInLowerCase)                  //转换为小写格式
            ) {
              tip(
                "Prop \"" + keyInLowerCase + "\" is passed to component " +
                (formatComponentName(tag || Ctor)) + ", but the declared prop name is" +
                " \"" + key + "\". " +
                "Note that HTML attributes are case-insensitive and camelCased " +
                "props need to use their kebab-case equivalents when using in-DOM " +
                "templates. You should probably use \"" + altKey + "\" instead of \"" + key + "\"."
              );
            }
          }
          checkProp(res, props, key, altKey, true) ||           //调用checkProp优先从props里拿对应的属性,其次从attrs里拿(对于attrs的话第五个参数为false,即会删除对应的attrs里的属性)
          checkProp(res, attrs, key, altKey, false);
        }
      }
      return res
    }

    复制代码

    checkProp是检测props或attrs是否含有key对应的值,如下:

    复制代码

    function checkProp (          //第2150行 检测prop是否存在
      res,
      hash,
      key,
      altKey,
      preserve
    ) {
      if (isDef(hash)) {              //如果hash存在
        if (hasOwn(hash, key)) {            //如果hash里面有定义了key
          res[key] = hash[key];
          if (!preserve) {
            delete hash[key];
          }
          return true
        } else if (hasOwn(hash, altKey)) {  //如果有驼峰的表示法,也找到了
          res[key] = hash[altKey];
          if (!preserve) {
            delete hash[altKey];
          }
          return true
        }
      }
      return false                          //如果在res里未找到则返回false
    }

    复制代码

     extractPropsFromVNodeData只是获取值,验证理验证和默认值是子组件完成执行的,执行到这里就获取到了props的值,例子里执行到这里等于

    整个对象会作为propsData属性保存到组件的VNode里面,如下:

     当子组件实例化的时候会执行_init()函数,首先会执行initInternalComponent函数,对于props的操作如下:

    复制代码

    function initInternalComponent (vm, options) {          //第4632行 子组件初始化子组件
      var opts = vm.$options = Object.create(vm.constructor.options);     //组件的配置信息
      // doing this because it's faster than dynamic enumeration. 
      var parentVnode = options._parentVnode;                             //该组件的占位符VNode
      opts.parent = options.parent;
      opts._parentVnode = parentVnode;
      opts._parentElm = options._parentElm;
      opts._refElm = options._refElm;
    
      var vnodeComponentOptions = parentVnode.componentOptions;           //占位符VNode初始化传入的配置信息
      opts.propsData = vnodeComponentOptions.propsData;                   //这就是上面经过extractPropsFromVNodeData()得到的propsData对象
      opts._parentListeners = vnodeComponentOptions.listeners;
      opts._renderChildren = vnodeComponentOptions.children;
      opts._componentTag = vnodeComponentOptions.tag;
    
      if (options.render) {
        opts.render = options.render;
        opts.staticRenderFns = options.staticRenderFns;
      }
    }

    复制代码

    这样组件实例化时就得到了propsData了,如下

    然后回到_init()初始化函数,会执行initState()函数,该函数首先会判断是否有props属性,如果有则执行initProps初始化props,如下:

    复制代码

    function initProps (vm, propsOptions) {     //第3319行 初始化props属性
      var propsData = vm.$options.propsData || {};                      //获取propsData属性,也就是例子里的{title:"Hello World"}
      var props = vm._props = {};
      // cache prop keys so that future props updates can iterate using Array
      // instead of dynamic object key enumeration.
      var keys = vm.$options._propKeys = [];                            //用于保存当前组件的props里的key   ;以便之后在父组件更新props时可以直接使用数组迭代,而不需要动态枚举键值
      var isRoot = !vm.$parent;
      // root instance props should be converted
      if (!isRoot) {
        toggleObserving(false);
      }
      var loop = function ( key ) {                                     //定义一个loop函数,一会儿会循环调用它
        keys.push(key);                                                   //保存key
        var value = validateProp(key, propsOptions, propsData, vm);       //执行validateProp检查propsData里的key值是否符合propsOptions里对应的要求,并将值保存到value里面
        /* istanbul ignore else */
        {
          var hyphenatedKey = hyphenate(key);
          if (isReservedAttribute(hyphenatedKey) ||
              config.isReservedAttr(hyphenatedKey)) {
            warn(
              ("\"" + hyphenatedKey + "\" is a reserved attribute and cannot be used as component prop."),
              vm
            );
          }
          defineReactive(props, key, value, function () {                 //将key变成响应式,同时也定义了props的key属性的值为value
            if (vm.$parent && !isUpdatingChildComponent) {
              warn(
                "Avoid mutating a prop directly since the value will be " +
                "overwritten whenever the parent component re-renders. " +
                "Instead, use a data or computed property based on the prop's " +
                "value. Prop being mutated: \"" + key + "\"",
                vm
              );
            }
          });
        }
        // static props are already proxied on the component's prototype
        // during Vue.extend(). We only need to proxy props defined at
        // instantiation here.
        if (!(key in vm)) {
          proxy(vm, "_props", key);
        }
      };
     
      for (var key in propsOptions) loop( key );                          //遍历每个props 依次调用loop()函数
      toggleObserving(true);
    }

    复制代码

    至此整个流程跑完了,前面说了extractPropsFromVNodeData只是获取值,而验证理验证和默认值就是在validateProp()函数内做的判断,如下:

    复制代码

    function validateProp (         //第1582行 检查props
      key,
      propOptions,
      propsData,
      vm
    ) {
      var prop = propOptions[key];                    //获取对应的值,例如:{type: null}
      var absent = !hasOwn(propsData, key);           //如果propsData没有key这个键名,则absent为true
      var value = propsData[key];                     //尝试获取propsData里key这个键的值
      // boolean casting
      var booleanIndex = getTypeIndex(Boolean, prop.type);          //调用getTypeIndex()含糊判断prop.type是否包含布尔类型
      if (booleanIndex > -1) {
        if (absent && !hasOwn(prop, 'default')) {
          value = false;
        } else if (value === '' || value === hyphenate(key)) {
          // only cast empty string / same name to boolean if
          // boolean has higher priority
          var stringIndex = getTypeIndex(String, prop.type);
          if (stringIndex < 0 || booleanIndex < stringIndex) {
            value = true;
          }
        }
      }
      // check default value
      if (value === undefined) {                        //如果value未定义
        value = getPropDefaultValue(vm, prop, key);         //尝试获取默认值
        // since the default value is a fresh copy,   
        // make sure to observe it.
        var prevShouldObserve = shouldObserve;
        toggleObserving(true);
        observe(value);
        toggleObserving(prevShouldObserve);
      }
      {
        assertProp(prop, key, value, vm, absent);           //判断Prop是否有效
      }
      return value                                      //最后返回value
    }

    复制代码

    剩下来就几个工具函数了,比较简单,大致如此。

    注:在Vue这么多属性里面,props是最有意思,最好玩的。虽然props的用法比较简单,但是它的原理实现我觉得是最复杂的,理解了props的实现原理,可以说是对Vue源码算是有比较大的深入了解了

    展开全文
  • vue props 属性值接受多个类型

    千次阅读 2020-09-08 16:57:14
    vue props 属性值接受多个类型 直接上代码: someData: { type: Array | Object, default () { return [] } } ... 如果我们自己写不限制类型的props,可以使用数组的形式 props:['someData'] 但是有时我们做...

    vue props 属性值接受多个类型

    直接上代码:

    props: {
    	someData: {
    		type: Array | Object,
    		default () {
    			return []
    		}
    	},
    	...
    }
    

    如果我们自己写不限制类型的props,可以使用数组的形式

    props:['someData']
    

    但是有时我们做已经搭好的框架,
    里面组件比较成熟都能直接用,
    但是发现别人写的组件里限制了类型,
    这时候我们由于业务需求想扩展组件功能增加一些类型,
    这时我们就需要用到第一种方法了

    希望这篇帖子能帮到你!

    展开全文
  • vue props属性值不能在本组件内修改

    千次阅读 2018-09-05 16:54:56
    有一个组件build,其中有一个props属性是floorId,当在build组件中修改floorId的值时,会报下面的错误 原因是:在Vue2中组件的props的数据流动改为了只能单向流动,即只能由组件外(调用组件方)通过组件的DOM...

    有一个组件build,其中有一个props属性是floorId,当在build组件中修改floorId的值时,会报下面的错误

    原因是:在Vue2中组件的props的数据流动改为了只能单向流动,即只能由组件外(调用组件方)通过组件的DOM属性attribute传递props给组件内,组件内只能被动接收组件外传递过来的数据,并且在组件内,不能修改由外层传来的props数据。

    展开全文
  • vue props 属性值接受多个类型 _@jie

    千次阅读 2021-05-12 10:35:16
    labelValue: { type: String | Number | Boolean, required: true, default: 0 }
    	labelValue: {
          type: String | Number | Boolean,
          required: true,
          default: 0
        }
    
    展开全文
  • vue组件的props属性

    2021-02-04 23:58:55
    VUE组件的props属性 vue组件可以通过props属性来从父组件获取值 props属性可以有以下几种写法// 数组写法 props: ['title', 'content', 'like'] // 对象写法 - 1 props: { title: String, // 指定title的类型,...
  • Vueprops属性

    2021-11-30 14:25:55
    props功能:让组件接受外部传过来的数据 (1):传递数据:<Demo name="xxx"/> (2):接受数据: 第一种:(只接收):props: ['name'] 第二种:(限制类型):props:{ name:Number } 第三种:(限制...
  • vue中组件的props属性(详)

    千次阅读 多人点赞 2021-10-27 17:15:27
    今天这篇文章,让你彻底学会props属性…… props主要用于组件的传值,他的工作就是为了接收外面传过来的数据,与data、el、ref是一个级别的配置项。
  • Vue:props属性值类型使用方法

    千次阅读 2020-03-28 15:34:27
    </head> <body> <div id="app"> <div>{{pmsg}}</div> <meun-item :pstr="pstr" :pnum="12" :pboo="true" :parr="parr" :pobj="pobj"></meun-item> </div> <script> //父组件想子组件传值 -props属性名类型 Vue....
  • vue组件之属性Props

    2020-12-24 12:52:41
    组件的属性和事件父子组件之间的通信父子组件之间的通信就是 props down,events up,父组件通过 属性props向下传递数据给子组件,子组件通过 事件events 给父组件发送消息。比如,子组件需要某个数据,就在内部定义...
  • 主要帮助大家简单的理解vueProps属性,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 我就废话不多说,看代码吧~ seller: { type: Object, default() { return {} } } seller: { type: Object, default: function () { ...当父组件没有传这个值或者值是空时,输出的话,返回: ...补充知识:解决vue
  • 如下所示: <!DOCTYPE html> <html lang=en xmlns:v-on=http://www.w3.org/1999/xhtml> <head> <meta charset=UTF-8> <title>Title</title>...child v-bind:my-message
  • Vue-属性传值Props

    万次阅读 多人点赞 2018-09-09 16:41:30
    1、父组件向子组件传值(属性传值) 当数据都在App.vue中时,如下图 需要将App.vue中的值传给User.vue,则需要在两者的契合点上进行绑定,如下图, 在User.vue中需要进行注册(如下图) 2、子组件向父组件...
  • VueProps属性概述

    千次阅读 2016-09-02 13:08:48
    使用 Props 传递数据组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接...子组件需要显式地用 props 选项 声明 propsVue.component('child', { // 声明 props props: ['msg'], // prop 可以
  • 主要介绍了vue - props 声明数组和对象操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 简单理解vueProps属性_javascript技巧

    千次阅读 2017-08-22 01:16:59
    简单理解vueProps属性_javascript技巧 摘要: 本文讲的是简单理解vueProps属性_javascript技巧, 本文实例为大家解析了vue中Props的属性,供大家参考,具体内容如下 使用 Props 传递数据 组件实例的作用...
  • props: ["listid], } 第二种用法(我推荐第二种用法, 相对比较严格) export default { 2 props: { 3 // 基础类型检测 (null 意思是任何类型都可以) 4 propA: null, 5 // 多种类型 6 propB: [String, Number], 7 ...
  • vue 属性props定义方法

    千次阅读 2019-05-27 16:55:00
    当子组件接收父组件传过来的值的时候,我们一般有两种方式来接收 不过大家好像都用第二种方式,我只有在不确定数据类型的时候... props: ["customer_id"], } 第二种: 1 export default { 2 props: { 3 ...
  • vueprops 中定义多属性对象,语法如下 例如定义 formValidate 对象,且 formValidate 中含有属性 city 和 name,默认 city 和 name 都是空 formValidate: { type: Object, default: ()=>{ return { ...
  • 使用 Props 传递数据 组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。 “prop” 是组件数据的一个字段,期望从父组件传下来。...Vue...
  • Vueprops的使用详解

    2020-08-27 08:28:28
    props属性是父子组件之间的通信桥梁。这篇文章主要介绍了Vue中props的使用,需要的朋友可以参考下
  • 今天小编就为大家分享一篇vue props对象validator自定义函数实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • Vueprops一定就是只读吗

    千次阅读 2020-07-31 22:45:22
    数据由父组件通过xhr请求获取,然后传参给子组件,在子组件中通过props接收,然后通过监听props的变化,将该值传给data。在很多业务场景中,子组件的详情数据都需要支持编辑操作,编辑操作通常是做两件事,一个是...
  • vue props

    2020-04-29 13:24:48
    props 验证 组件的 props 就是组件的参数,为了确保传入的...Vue.component('my-component', { props: { // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证) propA: Number, // 多个可能的类型 ...
  • Vue.component('my-component', { props: { // 基础的类型检查 (`null` 匹配任何类型) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,742
精华内容 20,296
关键字:

vue的props属性

vue 订阅