组件名
定义组件名的方式有两种:
使用 kebab-case
Vue.component('my-component-name', { /* ... */ })
例如 <my-component-name>
使用 PascalCase
Vue.component('MyComponentName', { /* ... */ })
使用:<my-component-name> 和 <MyComponentName>
全局注册

全局注册可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。
局部注册
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。


注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:

或者如果你通过 Babel 和 webpack 使用 ES2015 模块,那么代码看起来更像:

模块系统
Babel 和 webpack 的模块系统下,我们推荐创建一个 components 目录,并将每个组件放置在其各自的文件中。
然后你需要在局部注册之前导入每个你想使用的组件。例如,在一个假设的 ComponentB.js 或 ComponentB.vue 文件中:
import ComponentA from './ComponentA' import ComponentC from './ComponentC' export default { components: { ComponentA, ComponentC }, // ... }
现在 ComponentA 和 ComponentC 都可以在 ComponentB 的模板中使用了。
基础组件的自动化全局注册
可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们有时候会把它们称为基础组件,它们会在各个组件中被频繁的用到。会导致很多组件里都会有一个包含基础组件的长列表:

如果你恰好使用了 webpack (或在内部使用了 webpack 的 Vue CLI 3+),那么就可以使用 require.context 只全局注册这些非常通用的基础组件。这里有一份可以让你在应用入口文件 (比如 src/main.js) 中全局导入基础组件的示例代码:
import Vue from 'vue' import upperFirst from 'lodash/upperFirst' import camelCase from 'lodash/camelCase' const requireComponent = require.context( // 其组件目录的相对路径 './components', // 是否查询其子目录 false, // 匹配基础组件文件名的正则表达式 /Base[A-Z]\w+\.(vue|js)$/ ) requireComponent.keys().forEach(fileName => { // 获取组件配置 const componentConfig = requireComponent(fileName) // 获取组件的 PascalCase 命名 const componentName = upperFirst( camelCase( // 获取和目录深度无关的文件名 fileName .split('/') .pop() .replace(/\.\w+$/, '') ) ) // 全局注册组件 Vue.component( componentName, // 如果这个组件选项是通过 `export default` 导出的, // 那么就会优先使用 `.default`, // 否则回退到使用模块的根。 componentConfig.default || componentConfig ) })
记住全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生。
Prop
prop大小写
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名



改为
后正常显示。
Prop 类型
字符串数组形式列出的 prop:
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
但是,通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:
props: { title: String, likes: Number, isPublished: Boolean, commentIds: Array, author: Object, callback: Function, contactsPromise: Promise // or any other constructor }
这不仅为你的组件提供了文档,还会在它们遇到错误的类型时从浏览器的 JavaScript 控制台提示用户。
传递静态或动态 Prop
<blog-post title="My journey with Vue"></blog-post>
<!-- 动态赋予一个变量的值 --> <blog-post v-bind:title="post.title"></blog-post>

单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
prop验证
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
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 } } } }) 当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
自定义事件
事件命名问题
不同于组件和 prop,事件名不存在任何自动化的大小写转换。
this.$emit('myEvent')
则监听这个名字的 kebab-case 版本是不会有任何效果的:
<!-- 没有效果 --> <my-component v-on:my-event="doSomething"></my-component>
因此,我们推荐你始终使用 kebab-case 的事件名。
自定义组件的v-model
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:
【自定义组件的 v-model 】(自我总结)
可以双向绑定父子组件的值,(子组件通过事件改变子组件的值,父组件的值也回相对应的改变),绑定父组件的值改变,子组件的值也发生改变

自定义事件也可以用于创建支持 v-model 的自定义输入组件。记住: <input v-model="searchText"> 等价于: <input v-bind:value="searchText" v-on:input="searchText = $event.target.value" > 当用在组件上时,v-model 则会这样: <custom-input v-bind:value="searchText" v-on:input="searchText = $event" ></custom-input> 为了让它正常工作,这个组件内的 <input> 必须: 将其 value 特性绑定到一个名叫 value 的 prop 上 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出 写成代码之后是这样的: Vue.component('custom-input', { props: ['value'], template: ` <input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > ` }) 现在 v-model 就应该可以在这个组件上完美地工作起来了: <custom-input v-model="searchText"></custom-input>
自己写的一个input组件
<com-b v-model="text"></com-b>//父组件 {{text}} data:{ text:'' }, //子组件 model: { prop: 'text', //此处双向绑定着父组件的text 和子组件的text event: 'input'//个人理解当组件事件为oninput的时候 触发 }, props: { text: String }, template: ` <input type="text" :value = text @input="$emit('input', $event.target.value)" > `
.sync 修饰符
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。
vue中我们经常会用v-bind(缩写为:)给子组件传入参数。
或者我们会给子组件传入一个函数,子组件通过调用传入的函数来改变父组件的状态。
例如:
//父组件给子组件传入一个函数 <MyFooter :age="age" @setAge="(res)=> age = res"> </MyFooter> //子组件通过调用这个函数来实现修改父组件的状态。 mounted () { console.log(this.$emit('setAge',1234567)); }
这时子组件触发了父组件的修改函数使父组件的age修改成了1234567
这种情况比较常见切写法比较复杂。于是我们引出今天的主角 .sync
这时我们可以直接这样写
//父组件将age传给子组件并使用.sync修饰符。 <MyFooter :age.sync="age"> </MyFooter> //子组件触发事件 mounted () { console.log(this.$emit('update:age',1234567)); }
这里注意我们的事件名称被换成了update:age
update:是被固定的也就是vue为我们约定好的名称部分
age是我们要修改的状态的名称,是我们手动配置的,与传入的状态(props)名字对应起来
这样就完成了,是不是感觉简单了很多。
注意事项:
这里我们必须在事件执行名称前加上update:的前缀才能正确触发事件。
浙公网安备 33010602011771号