vue的一些注意点

Vue注意点

v-html

你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容插值。

利用标签模板,过滤 HTML 字符串,防止用户输入恶意内容。

function SaferHTML(templateData) {
    let s = templateData[0];
    console.log(s);
    for (let i = 1; i < arguments.length; i++) {
        let arg = String(arguments[i]);

        // Escape special characters in the substitution.
        s += arg.replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

        // Don't escape special characters in the template.
        s += templateData[i];
    }
    return s;
}

条件渲染

template不支持v-show

默认情况下在切换dom时相同的结构会被复用,如果不需要复用,需要添加key

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="1">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="2">
</template>

checkbox

多个复选框。v-model需要绑定到一个数组

//html
<div id='example-3'>
  <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
  <label for="jack">Jack</label>
  <input type="checkbox" id="john" value="John" v-model="checkedNames">
  <label for="john">John</label>
  <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
  <label for="mike">Mike</label>
  <br>
  <span>Checked names: {{ checkedNames }}</span>
</div>

//js
new Vue({
  el: '#example-3',
  data: {
    checkedNames: []
  }
})

多选时的select框同理

箭头函数

不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a)
vm.$watch('a', newValue => this.myMethod())。因为箭头函数是和父级上下文绑定在一起的,this 不会是如你所预期的 Vue 实例,经常导致 Uncaught TypeError: Cannot read property of undefined
Uncaught TypeError: this.myMethod is not a function 之类的错误。

数组更新检测

Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:push()、pop()、shift()、unshift()、splice()、sort()、reverse()。

变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异 (non-mutating method) 方法,例如:filter(), concat() 和 slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

注意事项

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的

为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue) 

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

你也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:

vm.$set(vm.items, indexOfItem, newValue)

为了解决第二类问题,你可以使用 splice:

vm.items.splice(newLength)

==Vue.set可改为vm.$set==

对象更改检测注意事项

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的

对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。例如,对于:

var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})

你可以添加一个新的 age 属性到嵌套的 userProfile 对象:

Vue.set(vm.userProfile, 'age', 27)

如果需要为已有对象赋予多个属性:

vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

删除属性用Vue.delete或者vm.$delete。

Vue.delete(vm.items,0);
//或者
vm.$delete(vm.items,0);

解析 DOM 模板时的注意事项

有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr> 和 <option>,只能出现在其它某些特定的元素内部。

这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

<table>
  <blog-post-row></blog-post-row>
</table>

这个自定义组件

<table>
  <tr is="blog-post-row"></tr>
</table>

需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:

单个根元素

每个组件必须只有一个根元素

<h3>{{ title }}</h3>
<div v-html="content"></div>

以上模板会报错,将其包裹在一个父元素内即可解决

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

组件名大小写

当组件名使用 kebab-case方式时,在引用这个自定义元素时必须使用 kebab-case
当组件名使用 PascalCase方式时,引用这个自定义元素时可使用 kebab-case 或者 PascalCase

但是,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的

事件名

跟组件和 prop 不同,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。

this.$emit('myEvent')

<my-component v-on:my-event="doSomething"></my-component>

以上监听是无法生效的,v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的)。因此,推荐始终使用 kebab-case 的事件名

事件处理

常规绑定方法

//html
<div id="example-2">
  <!-- `greet` 是在下面定义的方法名 -->
  <button v-on:click="greet">Greet</button>
</div>
//js
var example2 = new Vue({
  el: '#example-2',
  data: {
    name: 'Vue.js'
  },
  // 在 `methods` 对象中定义方法
  methods: {
    greet: function (event) {
      // `this` 在方法里指向当前 Vue 实例
      alert('Hello ' + this.name + '!')
      // `event` 是原生 DOM 事件
      if (event) {
        alert(event.target.tagName)
      }
    }
  }
})

内联 JavaScript 语句中调用方法

//html
<div id="example-3">
  <button v-on:click="say('hi', $event)">Say hi</button>
  <button v-on:click="say('what', $event)">Say what</button>
</div>
//js
new Vue({
  el: '#example-3',
  methods: {
    say: function (message, event) {
      alert(message)
    }
  }
})

v-model

<input v-model="searchText">
//等价于
<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

给组件添加 v-model 属性时,==默认会把 value 作为组件的属性,然后把 'input' 值作为给组件绑定事件时的事件名==

但是在单选框、复选框等类型的输入控件,需要的就不是默认的value特性以及input事件了,有两种方法进行修改

html

<base-checkbox v-model="lovingVue"></base-checkbox>
  1. 修改v-model语法糖
Vue.component('base-checkbox', {
  props:['value']
  template: `
    <input
      type="checkbox"
      v-bind:checked="value"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
  1. 在 Vue 2.2 版本,你可以在定义组件时通过 model 选项的方式来定制 prop/event:
Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

为组件添加原生事件

为v-on添加.native修饰符即可

<base-input v-on:focus.native="onFocus"></base-input>

特殊情况: 如果使用focus监听input元素,并且input元素被包裹在一个父元素中,.native监听器将默认失败

$attrs、$listeners、inheritAttrs

名词解释

$attrs--继承所有的父组件属性(除了prop传递的属性、class 和 style )

inheritAttrs:默认值true,继承所有的父组件属性(除props的特定绑定)作为普通的HTML特性应用在子组件的根元素上,如果你不希望组件的根元素继承特性设置inheritAttrs: false,但是class属性和style会继承。

$listeners--属性,它是一个对象,里面包含了作用在这个组件上的所有监听器,你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。

代码演示:

//HTML
<div id="app">
    <base-input v-model="a" placeholder="tip" label="name" class="a" :style="{color: 'red'}"></base-input>
</div>

//JS
Vue.component('base-input', {
    props: ['value'],
    template: `
    <label>
    {{$attrs.placeholder}}
    {{$attrs.label}}
      <input
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
        v-bind="$attrs">
    </label>
    `
});
var v = new Vue({
    el: '#app',
    data: {
        a: '123',
    }
});

因为inheritAttrs的默认值为ture,所以组件的根元素label将继承父组件的所有属性(除了class、style和props传递的属性);组件内的input则通过v-on="$attrs"绑定了父组件的属性。

渲染结果为:

<label placeholder="tip" label="name" class="a" style="color: red;">
    tip
    name
    <input placeholder="tip" label="name">
</label>

若将inheriAttrs值设为false,
根元素label将不会继承父组件的属性。

<label class="a" style="color: red;">
    tip
    name
    <input placeholder="tip" label="name">
</label>

$attrs可以打包父组件的属性,同样的,$listeners则打包父组件的事件

//html
<div id="app">
    <base-input @click="func" @focus="funf" v-model="a" placeholder="tip" label="name" class="a" :style="{color: 'red'}"></base-input>
</div>

//js
Vue.component('base-input', {
//  inheritAttrs: false,
    props: ['value'],
    template: `
    <label>
    {{$attrs.placeholder}}
    {{$attrs.label}}
      <input
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
        v-bind="$attrs"
        v-on="$listeners">
    </label>
    `
});
var v = new Vue({
    el: '#app',
    data: {
        a: '123',
    },
    methods: {
        func: function(){
            console.log('被点击了');
        },
        funf: function(){
            console.log('获得焦点');
        }
    },
});

插槽

如果组件没有包含一个

$nextTick()

如果数据变化后想获取真实dom中的内容,需要等待页面渲染完毕后再去获取所有的dom操作最好放在nextTick中

slot插槽

如果组件模板没有包含一个

<my-component>
    Your Profile
</my-component>

当有多个内容需要分配至相应插槽中,可以将内容包裹在设置了slot特性的

猜你喜欢

转载自www.cnblogs.com/y-dt/p/9787580.html