详解vue组件三大中心观点

媒介

本文主要引见属性、事宜和插槽这三个vue基本观点、运用要领及其轻易被疏忽的一些主要细节。假如你浏览他人写的组件,也能够从这三个部份睁开,它们能够协助你疾速相识一个组件的一切功用。

《详解vue组件三大中心观点》

本文的代码请猛戳github博客,纸上得来终觉浅,人人着手多敲敲代码!

一、属性

1.自定义属性props

prop 定义了这个组件有哪些可设置的属性,组件的中心功用也都是它来肯定的。写通用组件时,props 最好用对象的写法,如许能够针对每一个属性设置范例、默许值或自定义校验属性的值,这点在组件开辟中很主要,然则很多人却无视,直接运用 props 的数组用法,如许的组件往往是不严谨的。

// 父组件
 <props name='属性'
           :type='type'
           :is-visible="false"
           :on-change="handlePropChange"
           :list=[22,33,44]
           title="属性Demo"
           class="test1"
           :class="['test2']"
           :style="{ marginTop: '20px' }" //注重:style 的优先级是要高于 style
           style="margin-top: 10px">
  </props>
// 子组件
  props: {
    name: String,
    type: {
   //从父级传入的 type,它的值必需是指定的 'success', 'warning', 'danger'中的一个,假如传入这三个之外的值,都邑抛出一条正告
      validator: (value) => {
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    onChange: {
    //关于吸收的数据,能够是种种数据范例,一样也能够通报一个函数
      type: Function,
      default: () => { }
    },
    isVisible: {
      type: Boolean,
      default: false
    },
    list: {
      type: Array,
      // 对象或数组默许值必需从一个工场函数猎取
      default: () => []
    }
  }

从上面的例中,能够得出props 能够显现定义一个或一个以上的数据,关于吸收的数据,能够是种种数据范例,一样也能够通报一个函数。经由过程平常属性完成父向子通讯;经由过程函数属性完成子向父通讯

2.inheritAttrs

这是2.4.0 新增的一个API,默许情况下父作用域的不被认作 props 的特征绑定将会“回退”且作为一般的 HTML 特征应用在子组件的根元素上。可经由过程设置 inheritAttrs 为 false,这些默许行动将会被去掉。注重:这个选项不影响 class 和 style 绑定
上个例中,title属性没有在子组件中props中声明,就会默许挂在子组件的根元素上,以下图所示:

《详解vue组件三大中心观点》

3. data与props区分

  • 雷同点

二者选项里都能够寄存种种范例的数据,当行动操纵转变时,一切行动操纵所用到和模板所衬着的数据同时都邑发作同步变化。

  • 不同点

data 被称之为动态数据,在各自实例中,在任何情况下,我们都能够随便转变它的数据范例和数据结构,不会被任何环境所影响。

props 被称之为静态数据,在各自实例中,一旦在初始化被定义好范例时,基于 Vue 是单向数据流,在数据通报时一直不能转变它的数据范例,而且不允许在子组件中直接操纵 通报过来的props数据,而是须要经由过程别的手腕,转变通报源中的数据。至于如何转变,我们接下去细致引见:

4.单向数据流

这个观点涌现在组件通讯。props的数据都是经由过程父组件或许更高层级的组件数据或许字面量的体式格局举行通报的,不允许直接操纵转变各自实例中的props数据,而是须要经由过程别的手腕,转变通报源中的数据。那假如有时刻我们想修正通报过来的prop,有哪些要领呢?

  • 要领1:过渡到 data 选项中

在子组件的 data 中拷贝一份 prop,data 是能够修正的

export default {
  props: {
    type: String
  },
  data () {
    return {
      currentType: this.type
    }
  }
}

在 data 选项里经由过程 currentType吸收 props中type数据,相当于对 currentType= type举行一个赋值操纵,不仅拿到了 currentType的数据,而且也能够转变 currentType数据。

  • 要领2:应用盘算属性
export default {
  props: {
    type: String
  },
  computed: {
    normalizedType: function () {
      return this.type.toUpperCase();
    }
  }
}

以上两种要领虽能够在子组件间接修正props的值,但假如子组件想修正数据而且同步更新到父组件,却杯水车薪。在一些情况下,我们可能会须要对一个 prop 举行『双向绑定』,此时就引荐以下这两种要领:

  • 要领3:运用.sync
// 父组件
<template>
  <div class="hello">
    <div>
      <p>父组件msg:{{ msg }}</p>
      <p>父组件数组:{{ arr }}</p>
    </div>
    <button @click="show = true">翻开model框</button>
    <br />
    <demo :show.sync="show" :msg.sync="msg" :arr="arr"></demo>
  </div>
</template>

<script>
import Demo from "./demo.vue";
export default {
  name: "Hello",
  components: {
    Demo
  },
  data() {
    return {
      show: false,
      msg: "模仿一个model框",
      arr: [1, 2, 3]
    };
  }
};
</script>
// 子组件
<template>
  <div v-if="show" class="border">
    <div>子组件msg:{{ msg }}</div>
    <div>子组件数组:{{ arr }}</div>
    <button @click="closeModel">封闭model框</button>
    <button @click="$emit('update:msg', '浪里行舟')">
      转变笔墨
    </button>
    <button @click="arr.push('前端工匠')">转变数组</button> 
  </div>
</template>
<script>
export default {
  props: {
    msg: {
      type: String
    },
    show: {
      type: Boolean
    },
    arr: {
      type: Array //在子组件中转变通报过来数组将会影响到父组件的状况
    }
  },
  methods: {
    closeModel() {
      this.$emit("update:show", false);
    }
  }
};

《详解vue组件三大中心观点》

父组件向子组件 props 里通报了 msg 和 show 两个值,都用了.sync 修饰符,举行双向绑定。
不过.sync 虽好,但也有限定,比方:

1)不能和表达式一同运用(如 v-bind:title.sync="doc.title + '!'" 是无效的);
2)不能用在字面量对象上(如 v-bind.sync="{ title: doc.title }" 是没法一般事情的)。

  • 要领4:将父组件中的数据包装成对象通报给子组件

这是由于在 JavaScript 中对象和数组是经由过程援用传入的,所以关于一个数组或对象范例的 prop 来讲,在子组件中转变这个对象或数组自身将会影响到父组件的状况。比方上例中在子组件中修正父组件通报过来的数组arr,从而转变父组件的状况。

5.向子组件中通报数据时加和不加 v-bind?

关于字面量语法和动态语法,初学者可能在父组件模板中向子组件中通报数据时究竟加和不加 v-bind 会觉得疑惑。

v-bind:msg = ‘msg’

这是经由过程 v-bind 举行通报数据而且通报的数据并非一个字面量,双引号里的剖析的是一个表达式,一样也能够是实例上定义的数据和要领(实在就是援用一个变量)。

msg=’浪里行舟’

这类在没有 v-bind 的形式下只能通报一个字面量,这个字面量只限于 String 类量,字符串范例。那假如想经由过程字面量举行数据通报时,假如想通报非String范例,必需props名前要加上v-bind,内部经由过程实例寻觅,假如实例方没有此属性和要领,则默许为对应的数据范例。

:msg='11111' //Number 
:msg='true' //Bootlean 
:msg='()=>{console.log(1)}' //Function
:msg='{a:1}' //Object

二、事宜

1.事宜驱动与数据驱动

用原生JavaScript事宜驱动通常是如许的流程:

  • 先经由过程特定的选择器查找到须要操纵的节点 -> 给节点增加响应的事宜监听
  • 然后用户实行某事宜(点击,输入,退却等等) -> 挪用 JavaScript 来修正节点

这类形式对营业来讲是没有什么题目,然则从开辟本钱和效力来讲会比较不抱负,特别是在营业体系愈来愈巨大的时刻。另一方面,找节点和修正节点这件事,效力自身就很低,因而涌现了数据驱动形式。

Vue的一个中心头脑是数据驱动。所谓数据驱动,是指视图是由数据驱动天生的,我们对视图的修正,不会直接操纵 DOM,而是经由过程修正数据,其流程以下:

用户实行某个操纵 -> 反应到 VM 处置惩罚(能够致使 Model 更改) -> VM 层转变,经由过程绑定关联直接更新页面对应位置的数据

能够简朴地明白:数据驱动不是操纵节点的,而是经由过程假造的笼统数据层来直接更新页面。主要就是由于这一点,数据驱动框架才得以有较快的运转速率(由于不须要去折腾节点),而且能够应用到大型项目。

2.修饰符事宜

Vue事宜分为一般事宜和修饰符事宜,这里我们主要引见修饰符事宜。

Vue 供应了大批的修饰符封装了这些过滤和推断,让开辟者少写代码,把时候都投入的营业、逻辑上,只须要经由过程一个修饰符去挪用。我们先来思索如许题目:如何给这个自定义组件 custom-component 绑定一个原生的 click 事宜?

<custom-component>组件内容</custom-component>

假如你的回复是<custom-component @click="xxx">,那就错了。这里的 @click 是自定义事宜 click,并非原生事宜 click。绑定原生的 click 是如许的:

<custom-component @click.native="xxx">组件内容</custom-component>

现实开辟过程当中离不开事宜修饰符,罕见事宜修饰符有以下这些:

  • 表单修饰符

1).lazy

在默许情况下,v-model 在每次 input 事宜触发后将输入框的值与数据举行同步 。你能够增加 lazy 修饰符,从而转变成运用 change事宜举行同步。适用于输入完一切内容后,光标脱离才更新视图的场景。

2).trim

假如要自动过滤用户输入的首尾空缺字符,能够给 v-model 增加 trim 修饰符:

<input v-model.trim="msg">

这个修饰符能够过滤掉输入完暗码不小心多敲了一下空格的场景。须要注重的是,它只能过滤首尾的空格!首尾,中心的是不会过滤的。

3).number

假如想自动将用户的输入值转为数值范例,能够给 v-model 增加 number 修饰符:

<input v-model.number="value" type="text" />

《详解vue组件三大中心观点》

从上面例子,能够获得假如你先输入数字,那它就会限定你输入的只能是数字。假如你先输入字符串,那它就相当于没有加.number

  • 事宜修饰符
<!-- 阻挠单击事宜继承流传 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事宜不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符能够串连 -->
<a v-on:click.stop.prevent="doThat"></a>

三、插槽

插槽分为一般插槽和作用域插槽,实在二者很相似,只不过作用域插槽能够接收子组件通报过来的参数。

1.作用域插槽

我们无妨经由过程一个todolist的例子来相识作用域插槽。假如当item选中后,笔墨变成黄色(以下图所示),该如何完成呢?

《详解vue组件三大中心观点》

// 父组件
<template>
  <div class="toList">
    <input v-model="info" type="text" /> <button @click="addItem">增加</button>
    <ul>
      <TodoItem v-for="(item, index) in listData" :key="index">
        <template v-slot:item="itemProps"> // 这是个签字插槽
        // 个中itemProps的值就是子组件通报过来的对象
          <span
            :style="{
              fontSize: '20px',
              color: itemProps.checked ? 'yellow' : 'blue'
            }"
            >{{ item }}</span
          >
        </template>
      </TodoItem>
    </ul>
  </div>
</template>
<script>
import TodoItem from "./TodoItem";
export default {
  components: {
    TodoItem
  },
  data() {
    return {
      info: "",
      listData: []
    };
  },
  methods: {
    addItem() {
      this.listData.push(this.info);
      this.info = "";
    }
  }
};
</script>
// 子组件
<template>
  <div>
    <li class="item">
      <input v-model="checked" type="checkbox" />
      <slot name="item" :checked="checked"></slot> // 将checked的值通报给父组件
    </li>
  </div>
</template>
<script>
export default {
  data() {
    return {
      checked: false
    };
  }
};
</script>

值得注重:v-bind:style 的对象语法异常直观——看着异常像 CSS,但现实上是一个 JavaScript 对象。CSS 属性名能够用驼峰式 (camelCase) 或短横线分开 (kebab-case,记得用引号括起来) 来定名。

2.v-slot新语法

在 2.6.0 中,我们为签字插槽和作用域插槽引入了一个新的一致的语法 (即 v-slot 指令)。它庖代了 slot 和 slot-scope 。我们来思索个题目:雷同称号的插槽是兼并照样替代

  • Vue2.5版本,一般插槽兼并、作用域插槽替代
  • Vue2.6版本,都是替代(见下面例子)

我们经由过程一个例子引见下Vue2.6版本默许插槽、签字插槽和作用域插槽的新语法:

// 父组件
<template>
  <div class="helloSlot">
    <h2>2.6 新语法</h2>
    <SlotDemo>
      <p>默许插槽:default slot</p>
      <template v-slot:title>
        <p>签字插槽:title slot1</p>
        <p>签字插槽:title slot2</p>
      </template>
      <template v-slot:title>
        <p>new签字插槽:title slot1</p>
        <p>new签字插槽:title slot2</p>
      </template>
      <template v-slot:item="props">
        <p>作用域插槽:item slot-scope {{ props }}</p>
      </template>
    </SlotDemo>
  </div>
</template>
<script>
import Slot from "./slot";
export default {
  components: {
    SlotDemo: Slot
  }
};
</script>
// 子组件
<template>
  <div>
    <slot />
    <slot name="title" />
    <slot name="item" :propData="propData" />  // propData这个属性名能够恣意取
  </div>
</template>
<script>
export default {
  data() {
    return {
      propData: {
        value: "浪里行舟"
      }
    };
  }
};
</script>

《详解vue组件三大中心观点》

给人人引荐一个好用的BUG监控东西Fundebug,迎接免费试用!

迎接关注民众号:前端工匠,你的生长我们一同见证!
《详解vue组件三大中心观点》

参考文章

    原文作者:浪里行舟
    原文地址: https://segmentfault.com/a/1190000019335341
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞