Vue 模板书写注意点

关于 Vue 模板的语法,官方文档作了比较详细的介绍,建议读者先阅读完官网文档再继续阅读本文后续内容。html

下面介绍一些比较特殊的或者说须要注意的点。vue

v-bind 绑定对象

经过 v-bind 能够给组件传递 prop 数据,好比有组件 A :node

<template>
    <div>...</div>
</template>
<script>
export default {
    props: {
        name: String,
        age: Number,
        anotherProp: String
    }
};
</script>

那么给该组件传递 nameage 属性就能够写成这样:git

<A name="yibuyisheng" :age="27" :another-prop="'test'"></A>

注意,在传递 prop 数据的时候,模板里面的键名和声明处的键名对应是有讲究的:在模板里面,要么严格按照声明处的大小写,要么按照声明处的键名通过相似于 lodashsnakeCase 转换以后的形式书写。github

好比对于声明处的 anotherProp 属性,在模板里面对应写上 <A :anotherProp="'test'"></A> 或者 <A :another-prop="'test'"></A> ,是没有问题的。算法

若是写成 <A :another-Prop="'test'"></A> 或者 <A another-Prop="test"></A>,就会对应失败。(后面一种写法会在 DOM 树中看到 another-prop attributetypescript

虽然,大部分时候,都不用太去关心模板标签和属性的大小写问题(毕竟绝大多数时候写的都是 HTML 模板),可是有的属性,仍是要当心处理大小写问题的,好比 svgviewBox 属性:api

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg"
     width="150" height="100" viewBox="0 0 3 2">

  <rect width="1" height="2" x="0" fill="#008d46" />
  <rect width="1" height="2" x="1" fill="#ffffff" />
  <rect width="1" height="2" x="2" fill="#d2232c" />
</svg>

默认状况下,对于传递的未声明的属性,都会采用 setAttribute 设置到相应 DOM 元素上面去,好比:app

<A some-prop="some value"></A>

这个 some-prop 会经过 setAttribute 设置到 A 组件根元素的属性上面去。dom

而对于一些特殊属性,是须要设置到 DOM 元素对象上去的,好比 input[type="checked"]checked 属性。对于这些属性, Vue 内部作了默认配置,固然也能够经过全局的 Vue.config.mustUseProp 配置覆盖默认配置。

另外,经过 v-bindprop 修饰符,能够直接给相应的 DOM 节点对象设置属性,好比:

<div v-bind:name-attr.prop="'haha'"></div>
<!-- 缩写形式 -->
<div :name-attr.prop="'haha'"></div>

会被转换成大体以下代码:

// 属性名作驼峰转换
divElement.nameAttr = 'haha';

注意,以下形式写法:

<div name-attr.prop="haha"></div>

会被转换成大体以下代码:

divElement.setAttribute('name-attr.prop', 'haha');

若是 div 换成 A 组件,那么相应的属性操做就会发生在 A 组件的根元素上面。

最后,经过 v-bind 能够批量动态地设置属性:

<div v-bind="{id: 'list', name: 'yibuyisheng'}"></div>
<!-- 等同于,可是上述优点在于“大量属性”、“动态属性键” -->
<div id="list" name="yibuyisheng"></div>

Vue diff

Vue diff 逻辑有不少文章都作了介绍,能够参看这篇文章

此处主要强调因为 diff 算法,而形成的写模板必须注意的点。

key

官方有一些关于 key介绍

在实际开发中, key 主要用于解决同级 DOM 元素复用引发的 bug ,以及作列表渲染优化。

在列表渲染中, Vue 会尽可能复用已有 DOM 节点元素。默认状况下,对于被循环元素,会有 :key="index" 的设置,对于这中默认渲染模式,官网有一句很是很是重要的描述:

这个默认的模式是高效的,可是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。

有两个须要搞清楚的点:

  • 什么是子组件状态?

    子组件状态就是不受 prop 属性控制的状态。好比组件 B :

    <template>
        <div>{{ instanceCounter }}</div>
    </template>
    <script>
    let counter = 1;
    export default {
        data() {
            return {
                instanceCounter: counter++
            };
        }
    };
    </script>

    对于组件 B 来讲, instanceCounter 就是子组件状态。

  • 什么是临时 DOM 状态?

    基本全部未受 Vue prop 控制的,可是自身又能随交互变化的状态,都算做临时 DOM 状态。好比不受控制的 input.valueinput.checked 等等。

从根本原理上来说,全部没在 VNode 中的 data 属性上表达的状态,都算是相应组件或 DOM 节点的内部状态,都会存在 key 风险

明确了上面两个概念以后,咱们看一个例子:

import Vue from 'vue';
import { ThisTypedComponentOptionsWithRecordProps } from 'vue/types/options';

let counter = 1;
const Item: ThisTypedComponentOptionsWithRecordProps<Vue, {instanceCounter: number;}, {}, {}, {}> = {
    template: '<div class="item"><slot></slot> --{{ instanceCounter }}--</div>',
    data() {
        return {
            instanceCounter: counter++
        };
    }
};
Vue.component('Item', Item);

const KeyComponent: ThisTypedComponentOptionsWithRecordProps<Vue, {items: Array<{id: string;}>;}, {}, {}, {}> = {
    template: `
        <div>
            <Item v-for="item in items" @click="handle1" :key="item.id">{{ item.id }}</Item>
            <button @click="add">+</button>
        </div>
    `,
    data() {
        return {
            items: [
                {
                    id: '123'
                },
                {
                    id: '456'
                }
            ]
        };
    },
    methods: {
        add() {
            this.items.splice(1, 0, {
                id: '789'
            });
        }
    }
};

Vue.component('KeyComponent', KeyComponent);

new Vue({
    el: '#app',
    template: '<KeyComponent />'
});

在第一次点击 KeyComponent 组件中的按钮以后,输出结果为:

123 --1--
789 --3--
456 --2--

若是去掉 KeyComponentItemkey 属性设置,而后刷新页面,第一次点击 KeyCOmponent 组件中的按钮,输出结果为:

123 --1--
789 --2--
456 --3--

能够看出,只有加了正确的 key ,新插入的 768 组件才会对应到新建立的组件。

render

render 方法必需要返回一个 VNode 实例。

若是想返回一个文本节点怎么办呢?

能够借助于 createElement() 实现:

import Vue from 'vue';
import { ThisTypedComponentOptionsWithRecordProps } from 'vue/types/options';

const Test: ThisTypedComponentOptionsWithRecordProps<Vue, {}, {}, {}, {}> = {
    render(createElement) {
        const nodes = createElement('div', '文本内容').children;
        if (!nodes) {
            throw new Error('error');
        }
        return nodes[0];
    }
};
Vue.component('Test', Test);

更多关于 Vue 的文章参见此处

相关文章
相关标签/搜索