vue中v-bind的应用

208 阅读2分钟

定义

主要对html标签或组件属性进行绑定

使用

单个属性

<h2 v-bind:title="title">...</h2>
//等价于
<h2 :title="title">...</h2>
data() {
  return {
    title: '111'
  };
}

多个属性

<div v-bind="{ id: 'container', class: 'wrapper', 'data-attr': 'value' }"></div>

<div v-bind="attrsObject"></div>

data() {
  return {
    attrsObject: {
      id: 'main',
      class: 'container',
      'data-custom': '123'
    }
  };
}

场景应用

属性继承

再二次封装组件可以利用 v-bind + $attrs 实现属性方法继承传递

只要是在子组件未具体声明的属性都会继承,如 子组件定义了id为child2,就不会接收父组件的child

父组件

<template>
  <ChildComponent id="child" class="custom-class" data-custom="123" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent,
  },
};
</script>

子组件

<template>
  <div v-bind="$attrs" id="child2"  >
    <!-- 子组件内容 -->
  </div>
</template>

<script>
export default {
  inheritAttrs: false, // 禁用根节点默认的属性继承
};
</script>

输出的html

<div data-v-363bee45="" id="child2" class="custom-class" data-custom="123"></div>

v-model 特殊处理

由于v-model 是语法糖,等价于 声明了modelValue和 @update:modelValue ,

<MidComponent v-model="parentData" /> 
<!-- 等价于 -->
<MidComponent :modelValue="parentData" @update:modelValue="$event => parentData = $event" /> 

由于声明了。所以$attrs 是拿不到的,只能人为再声明,同时最终操作组件要定义该属性

ParentComponent

<template>
   <MidComponent v-model="parentData" /> 
   <!-- <MidComponent :modelValue="parentData" @update:modelValue="$event => parentData = $event" />  -->
  </template>
  
  <script>
  import MidComponent from './MidComponent.vue';
  import ChildComponent from './ChildComponent.vue';
  
  export default {
    components: {
        MidComponent,
        ChildComponent,
    },
    data() {
        return {
            parentData:  'xxxx'
        };
        }
  };
  </script> 

MidComponent 中间组件直接透传$attrs

<!-- 中间组件 -->
<template>
  <ChildComponent v-bind="$attrs"  />
</template>

<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: {
    ChildComponent,
  },
  inheritAttrs: false,
};
</script>

ChildComponent.vue 子组件需要 定义操作的属性+ 声明回调的事件

<!-- 子组件 --> 
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

<script>
export default {
  props: ['modelValue'],
};
</script>

inheritAttrs理解

inheritAttrs默认为true,即自动继承上一个组件的所有非prop的属性到根普通html节点,

注意是普通html节点,也就是说如果只有一个子组件同时是根组件,也不会自动继承

即 下面代码无法实现属性继承

<template>
  <ChildComponent   />
</template>

<script>
export default {
  inheritAttrs: true,
};
</script>

只能具体显示的把$atters 告诉 ChildComponent

<template>
  <ChildComponent v-bind="$attrs"  />
</template>

<script>
export default {
  inheritAttrs: false,
};
</script>

底层实现

通过遍历v-bind绑定的对象属性,赋值给当前渲染的标签

// 模拟 _b 函数
function bindObject(data, value) {
  if (value) {
    for (const key in value) {
      if (value.hasOwnProperty(key)) {
        data[key] = value[key];
      }
    }
  }
  return data;
}

// 模拟渲染函数
function render() {
  const attrsObject = {
    id: 'main',
    class: 'container',
    'data-custom': '123',
  };
  const data = bindObject({}, attrsObject);
  return createElement('div', data);
}

// 模拟创建 DOM 元素
function createElement(tag, data) {
  const el = document.createElement(tag);
  for (const key in data) {
    if (data.hasOwnProperty(key)) {
      el.setAttribute(key, data[key]);
    }
  }
  return el;
}

// 测试
const divElement = render();
console.log(divElement); // <div id="main" class="container" data-custom="123"  ></div>

嵌套对象

由于vue只能遍历一层,所以会直接输出属性[object Object]

  const attrsObject = {
    id: 'main',
    class: 'container',
    'data-custom': '123',
    testObj : {a:1,b:2}
  };

<div id="main" class="container" data-custom="123"  testObj="[object Object]" ></div>

1.提前转json

  const attrsObject = {
    id: 'main',
    class: 'container',
    'data-custom': '123',
    testObj : JSON.stringify({a:1,b:2})
  };

如需要嵌套对象,提前转化成json字符串


<div id="main" class="container" data-custom="123"  testObj="[object Object]" ></div>

2.style 单独处理

一般我们用style 定义成对象,可以针对style单独解构处理

<div v-bind="attrsObject" :style="attrsObject.style"></div>
data() {
  return {
    attrsObject: {
      id: 'main',
      class: 'container',
      style: {
        color: 'red',
        fontSize: '14px'
      }
    }
  };
}

输出结果

<div
  id="main"
  class="container"
  style="color: red; font-size: 14px;"
></div>

源码

github.com/mjsong07/co…