vue笔记2
事件监听listeners属性与$attrs属性
attrs属性
$attrs
属性包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。
当一个组件没有声明任何prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过
v-bind="this.$attrs"
传入内部组件——在创建高级别的组件时非常有用,通常多层组件嵌套时,使用他可以简化代码。
简单点讲就是包含了所以父组件在子组件上设置的属性(除了prop传递的属性、class 和 style )。
<div id="app">
<base-input
label="姓名"
class="name-input"
placeholder="请输入姓名"
test-attrs="$attrs"
></base-input>
</div>
Vue.component("base-input", {
inheritAttrs: true, //此处设置禁用继承特性
props: ["label"],
template: `
<label>
{{label}}-
{{$attrs.placeholder}}-
<input v-bind="$attrs"/>
</label>
`,
mounted: function() {
console.log(this.$attrs);//会输出test-attrs和placeholder
}
});
const app = new Vue({
el: "#app"
});
listeners属性
想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用v-on
的 .native
修饰符,
但是某些组件可能会对原生的dom元素进行重构,那么.native
修饰符将无法监听到事件。
vue提供$listeners
属性,它包含了作用于组件上的所有监听器。使用他可以获取到所有监听器
假如有三个层级的组件嵌套A-》B-》C,子组件触发父组件通常我们使用v-on
在父组件绑定事件,并在子组件中使用this.$emit()
触发,例如在B中触发A的test事件就是如此,那么在C中如果想触发A的test事件呢?此时,在B中调用组件时使用
<C v-on="$listeners"></C>
在组件C中就可以触发A的test事件了
.sync 修饰符
在使用v-bind
和props
来进行组件数据流传递时,它是单向的数据流传递,
也就是由父组件将数据传递到子组件,vue的这种设计是为了避免数据流传递混乱,
但是在某些场景,我们还是需要在子组件中改变数据,使用.sync
修饰符可以更新prop
。
父组件调用时:
<text-document v-bind:title.sync="doc.title"></text-document>
子组件触发改变:
this.$emit('update:title', newTitle)
插槽
插槽内容
插槽,你可以理解为使用插槽,它将允许你在组件标签中内嵌一些内容,包括文字,html代码、组件等,
并且能够在组件模板中渲染出来。插槽实现的内容分发,在开发组件插件时有用。
例如你在调用组件时内嵌一些内容
<navigation-link url="/profile">
<span class="fa fa-user"></span>
Your Profile
</navigation-link>
然后在组件的模板中使用<slot></slot>
去接受这些内容,在模板渲染时的地方会被你内嵌的内容代替,从而渲染出来
<a v-bind:href="url" class="nav-link">
<slot></slot>
</a>
渲染结果:
<a v-bind:href="url" class="nav-link">
<span class="fa fa-user"></span>
Your Profile
</a>
插槽的后备内容
插槽的后备内容实际上就是插槽内容的默认值,在设置了插槽却没有传入内容时,插槽会默认渲染的内容。
<button type="submit">
<slot>Submit</slot>
</button>
在调用组件时没有传入插槽内容的话,默认渲染Submit。
具名插槽
当我们需要在一个组件里面使用多个不同的插槽时,可以使用具名插槽,具名插槽的设计,使得插槽内容的输入更加灵活,解耦性更高。
使用:
1.组件模板中,给 <slot></slot
>进行命名 <slot name="slotName"></slot>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
2.在组件调用,插槽内容传入时,使用v-slot = 'slotName'
,值得注意的是v-slot
可以缩写为#
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
作用域插槽
在插槽使用时,有时候需要在父级中动态的改变插槽后备内容,而插槽的后备内容渲染的是子级的内容,那么在父级中就无法访问
<span>
<slot>{{ user.lastName }}</slot>
</span>
我们可能想换掉备用内容,用名而非姓来显示。如下:
<current-user>
{{ user.firstName }}
</current-user>
上述代码块是不会成功的。那么我们需要使用作用域插槽来实现,
为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 <slot>
元素的一个 attribute 绑定上去:
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
绑定在 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,
我们可以使用带值的 v-slot
来定义我们提供的插槽 prop 的名字:
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
这里你可以理解为通过插槽 propv-bind:user="user"
,将子级的user暴露给父级,
父级再通过v-slot:default="slotProps"
来接收,并且使用了一个别名slotProps
来访问user,
从而实现在父级访问子级内容,来动态修改插槽后备内容。
vue自定义指令
new Vue({
el:
data:
directives:{//自定义指令
change:{//change是自定义指令名称v-change
//指令的狗子函数
bind:function(){},//指令绑定到元素时
inserted:function(){},//被绑定元素插入父节点时调用。
update:function(){},//如果调用指令时,传递参数、参数变化此函数执行
componentUpdated:function(){},//指令所在组件的VNode及其子VNode全部更新后调用。
unbind:function(){},//解除绑定的元素
}
}
})
钩子函数参数
- el:指令所绑定的元素,可以用来直接操作 DOM 。
- binding:一个对象,包含以下属性:
- name:指令名,不包括 v- 前缀。
- value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
- oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- expression:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。
- arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。常用语动态指令出参数传递。
- modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
- vnode:Vue 编译生成的虚拟节点。
- oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
过滤器
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值
和v-bind
表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
你可以在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}