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, "&") .replace(//g, ">"); // Don't escape special characters in the template. s += templateData[i]; } return s;}
条件渲染
template不支持v-show
默认情况下在切换dom时相同的结构会被复用,如果不需要复用,需要添加key
checkbox
多个复选框。v-model需要绑定到一个数组
//htmlChecked names: { { checkedNames }}//jsnew 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.setVue.set(vm.items, indexOfItem, newValue) // Array.prototype.splicevm.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>,只能出现在其它某些特定的元素内部。
这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:
这个自定义组件 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:
需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:
- 字符串 (例如:template: '...')
单个根元素
每个组件必须只有一个根元素
{ { title }}
以上模板会报错,将其包裹在一个父元素内即可解决
{ { title }}
组件名大小写
当组件名使用 kebab-case方式时,在引用这个自定义元素时必须使用 kebab-case
当组件名使用 PascalCase方式时,引用这个自定义元素时可使用 kebab-case 或者 PascalCase但是,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的
事件名
跟组件和 prop 不同,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。
this.$emit('myEvent')
以上监听是无法生效的,v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的)。因此,推荐始终使用 kebab-case 的事件名
事件处理
常规绑定方法
//html//jsvar 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//jsnew Vue({ el: '#example-3', methods: { say: function (message, event) { alert(message) } }})
v-model
//等价于
给组件添加 v-model 属性时,==默认会把 value 作为组件的属性,然后把 'input' 值作为给组件绑定事件时的事件名==
但是在单选框、复选框等类型的输入控件,需要的就不是默认的value特性以及input事件了,有两种方法进行修改
html
- 修改v-model语法糖
Vue.component('base-checkbox', { props:['value'] template: ` `})
- 在 Vue 2.2 版本,你可以在定义组件时通过 model 选项的方式来定制 prop/event:
Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' }, props: { checked: Boolean }, template: ` `})
为组件添加原生事件
为v-on添加.native修饰符即可
特殊情况: 如果使用focus监听input元素,并且input元素被包裹在一个父元素中,.native监听器将默认失败
$attrs、$listeners、inheritAttrs
名词解释
$attrs--继承所有的父组件属性(除了prop传递的属性、class 和 style )
inheritAttrs:默认值true,继承所有的父组件属性(除props的特定绑定)作为普通的HTML特性应用在子组件的根元素上,如果你不希望组件的根元素继承特性设置inheritAttrs: false,但是class属性和style会继承。
$listeners--属性,它是一个对象,里面包含了作用在这个组件上的所有监听器,你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。
代码演示:
//HTML//JSVue.component('base-input', { props: ['value'], template: ` `});var v = new Vue({ el: '#app', data: { a: '123', }});
因为inheritAttrs的默认值为ture,所以组件的根元素label将继承父组件的所有属性(除了class、style和props传递的属性);组件内的input则通过v-on="$attrs"绑定了父组件的属性。
渲染结果为:
若将inheriAttrs值设为false,
根元素label将不会继承父组件的属性。$attrs可以打包父组件的属性,同样的,$listeners则打包父组件的事件
//html//jsVue.component('base-input', {// inheritAttrs: false, props: ['value'], template: ` `});var v = new Vue({ el: '#app', data: { a: '123', }, methods: { func: function(){ console.log('被点击了'); }, funf: function(){ console.log('获得焦点'); } },});
插槽
如果组件没有包含一个元素,则任何传入它的内容都会被抛弃。
$nextTick()
如果数据变化后想获取真实dom中的内容,需要等待页面渲染完毕后再去获取所有的dom操作最好放在nextTick中
slot插槽
如果组件模板没有包含一个 元素,则任何传入它的内容都会被抛弃。
Your Profile
当有多个内容需要分配至相应插槽中,可以将内容包裹在设置了slot特性的中
//html这是标题
这是段落
百度盒子//jsmy-component{ template:'#my'}
如果没有设置name属性,或者设了name值为“default”,name该插槽为默认插槽,它将会把未匹配到插槽的内容统一分配至默认插槽中
//html这是标题
这是段落
百度//jsmy-component{ template:'#my'}
上面代码中,h1会被保存在name为header的slot中,而p、a标签将会被保存在默认插槽中。
插槽标签内部加入内容可以起到默认值效果,
如果父组件为这个插槽提供了内容,则默认的内容会被替换掉。
作用域插槽
//todo-list模板
- { { todo.text }}
假设我们的todo-list组件被多个地方调用,而我们希望能在不同的地方调用组件的时候,组件的todo.text不仅限于以li的形式渲染,而是能以自定义的形式渲染,这时,作用域插槽可以满足:
//html//js//todo-list模板 { {slotProps.text}}
首先,在todo-list模板中,将li替换为slot,意味着slot具体被渲染成什么将由html中的todo-list组件的内容决定;接下来,在todo-list组件内添加template标签并设置slot-scope属性来接收slot所绑定的todo属性。就此,todo对象传递给了slotProps,todo-list组件内的li可以随意替代为其他标签。
关于
我们之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件:
当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。这时,我们在外围包裹keep-alive即可