从零开始的vue学习笔记(四)
组件注册
- 组件名
Vue.component('my-component-name', { /* ... */ })
这里的
my-component-name
就是组件名,组件名的取法可以参考指南kebab-case写法(-连接单词)
推荐的写法
定义:Vue.component('my-component-name', { /* ... */ })
用法:
<my-component-name></my-component-name>
PascalCase写法(单词首字母大写)
Vue.component('MyComponentName', { /* ... */ })
- 全局注册
Vue.component('my-component-name', { /* ... */ })
- 局部注册
先用一个普通的 JavaScript 对象来定义组件:var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
然后在
components
选项中定义你想要使用的组件:new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。
注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:var ComponentA = { /* ... */ } var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}
或者如果你通过 Babel 和 webpack 使用 ES2015 模块,那么代码看起来更像:
import ComponentA from './ComponentA.vue' export default {
components: {
ComponentA
},
// ...
}
- 模块系统
通过import/require
使用一个模块系统- 模块系统中局部注册
import ComponentA from './ComponentA'
import ComponentC from './ComponentC' export default {
components: {
ComponentA,
ComponentC
},
// ...
}
- 基础组件的自动化全局注册
示例代码
prop
prop大小写(camelCase vs kebab-case)
HTML 中的特性(属性)名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
因此,
强烈建议
用kebab-case
写法。prop 类型
通常,以字符串数组形式列出 prop:props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
但是,通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
传递静态或动态prop
传递静态值:<blog-post title="My journey with Vue"></blog-post>
传递动态值
<!-- 动态赋予一个变量的值 -->
<blog-post v-bind:title="post.title"></blog-post> <!-- 动态赋予一个复杂表达式的值 -->
<blog-post
v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>
实际上,能传递的值包括:字符串、数字、布尔值、数组、对象、对象所有属性。
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
prop验证
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
上面的
type
可以是原生构造函数的一个:String
,Number
,Boolean
,Array
,Object
,Date
,Function
,Symbol
。非 Prop 的特性
一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性。- 替换/合并已有的特性
对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值,class
和style
特性会稍微智能一些,即两边的值会被合并起来。 - 禁用特性继承
组件的选项中设置inheritAttrs: false
,适合配合实例的 $attrs 属性使用:Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})
- 替换/合并已有的特性
自定义事件
事件名
不同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配
监听这个事件所用的名称:this.$emit('myEvent')
则监听这个名字的 kebab-case 版本是不会有任何效果的:
<!-- 没有效果 -->
<my-component v-on:my-event="doSomething"></my-component>
推荐
始终使用 kebab-case 的事件名
自定义组件的 v-model
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)"
>
`
})
<base-checkbox v-model="lovingVue"></base-checkbox>
将原生事件绑定到组件
使用 v-on 的 .native 修饰符:<base-input v-on:focus.native="onFocus"></base-input>
Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
// `Object.assign` 将所有的对象合并为一个新对象
return Object.assign({},
// 我们从父级添加所有的监听器
this.$listeners,
// 然后我们添加自定义监听器,
// 或覆写一些监听器的行为
{
// 这里确保组件配合 `v-model` 的工作
input: function (event) {
vm.$emit('input', event.target.value)
}
}
)
}
},
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
`
})
.sync 修饰符
以update:myPropName
的模式触发事件this.$emit('update:title', newTitle)
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
缩写:
<text-document v-bind:title.sync="doc.title"></text-document>
同时设置多个 prop :
<text-document v-bind.sync="doc"></text-document>
插槽
插槽内容
<navigation-link url="/profile">
Your Profile
</navigation-link>
<navigation-link>
的模板中:<a v-bind:href="url" class="nav-link">
<slot></slot>
</a>
则
Your Profile
会替换<slot></slot>
部分。Your Profile
可以是HTML代码或者其他插件。编译作用域
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。<navigation-link url="/profile">
Clicking here will send you to: {{ url }}
<!--
这里的 `url` 会是 undefined,因为 "/profile" 是
_传递给_ <navigation-link> 的而不是
在 <navigation-link> 组件内部定义的。
-->
</navigation-link>
后备内容(默认值)
<button type="submit">
<slot>Submit</slot>
</button>
这里的
Submit
就是默认值。具名插槽
<slot>
元素有一个特殊的特性:name
。这个特性可以用来定义额外的插槽:<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
一个不带
name
的<slot>
出口会带有隐含的名字“default”。
在一个<template>
元素上使用v-slot
指令,并以 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>
作用域插槽
绑定在<slot>
元素上的特性被称为插槽prop
。现在在父级作用域中,我们可以给 v-slot 带一个值来定义我们提供的插槽prop
的名字:<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
独占默认插槽的缩写语法
<current-user v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</current-user>
解构插槽
Prop
<current-user v-slot="{ user }">
{{ user.firstName }}
</current-user>
动态插槽名
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>
具名插槽的缩写
(
v-slot:
) 替换为字符#
:其它示例(略)
动态组件&&异步组件
在动态组件上使用
keep-alive
曾经在一个多标签的界面中使用is
特性来切换不同的组件:<component v-bind:is="currentTabComponent"></component>
可以用一个
<keep-alive>
元素将其动态组件包裹起来,避免切换的时候重新渲染:<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
异步组件(略)
处理边界情况
这些特殊场景和危险情况需要留心~
访问元素 & 组件
- 访问根实例
$root
属性 - 访问父级组件实例
$parent
属性 - 访问子组件实例或子元素
ref
特性 - 依赖注入
新的实例选项:provide
和inject
。
- 访问根实例
程序化的事件侦听器
- 通过
$on(eventName, eventHandler)
侦听一个事件 - 通过
$once(eventName, eventHandler)
一次性侦听一个事件 - 通过
$off(eventName, eventHandler)
停止侦听一个事件
- 通过
循环引用
- 递归组件
- 组件之间的循环引用
模板定义的替代品
- 内联模板
- X-Template
控制更新
- 强制更新
$forceUpdate
- 通过
v-once
创建低开销的静态组件
- 强制更新
最新文章
- IOS管理文件和目录
- 34、JS/AJAX
- WPF 文本框添加水印效果
- Android 如何设置默认语言
- NSString+URLEncoding.h --使用Obj-C对数据等进行URLEncoding编码
- 学习zepto.js(原型方法)
- 虚拟机网络配置详解(NAT、桥接、Hostonly)
- python利用for..in遍历,while循环嵌套编译九九乘法表的几种模式
- 部署 Helm - 每天5分钟玩转 Docker 容器技术(162)
- 剑指Offer——银行网申内容模版
- 洛谷 P2725 解题报告
- Linux时间子系统之五:低分辨率定时器的原理和实现
- win10双系统安装卸载ubuntu
- Java探针
- BZOJ.3165.[HEOI2013]Segment(李超线段树)
- linux文本格式转换
- 线程使用中常见的错误-“System.InvalidOperationException”线程间操作无效: 从不是创建控件“ ”的线程访问它。
- Kali xrdp远程桌面
- R语言做条形图时候,离散变量和连续型变量的区别
- Android 热修复 Tinker接入及源代码浅析
热门文章
- 区间dp专题
- hihocoder #1608 : Jerry的奶酪(状压dp)
- CSS特效集锦:视觉魔法的碰撞与融合(二)
- JS-特效 ~ 04. client对象、网页可视区域的宽高、client / offset / scroll 三大家族的区别、冒泡事件、事件委托、获取内嵌式和外链式属性getStyle(ele,attr) ;、缓动动画封装
- 【LeetCode】524-通过删除字母匹配到字典里最长单词
- 学习笔记-Unity3d代码实现Windows10加载圈圈的效果
- Java 内存溢出分析
- DirectX12 3D 游戏开发与实战第三章内容
- SpringBoot的注解注入功能移植到.Net平台(开源)
- SpringCloud-Hystrix Dashboard 之 Unable to connect to Command Metric Stream