本页目录
组件的分类
- 全局组件 : 可以声明一次在任何地方使用(一般写插件的时候全局使用的多一点)
- 局部组件: 必须告诉这个组件属于谁(一般用局部比较好)
props 是只读的,vue 底层会检测你对 props 的修改,如果进行了修改,控制台会报错,必须修改,就复制一份到 data 中,通过 data 去修改数据。
我们在 data 里面重新定义一个变量去接收 props 属性。这个变量最好不要重名,重名的话,优先获取 props 属性值,优先级 props>data。
全局组件(component)
全局注册的组件可以在随后创建的 app 实例模板中使用,也包括根实例组件树中的所有子组件的模板中
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <runoob></runoob> <!-- 组件间数据相互独立 --> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
<script> // 创建一个Vue 应用 const app = Vue.createApp({})
// 定义一个名为 runoob的新全局组件 app.component('runoob', { template: '<h2>自定义组件!</h2>' }) // 定义一个名为 button-counter的新全局组件 app.component('button-counter', { data() { return { count: 0 } }, template: ` <button @click="count++"> 点了 {{ count }} 次! </button>` })
app.component('runoob', { template: '<h2>自定义组件!</h2>' }) app.mount('#app') </script>浏览器渲染
原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <runoob></runoob> <!-- 组件间数据相互独立 --> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
<script> // 创建一个Vue 应用 const app = Vue.createApp({})
// 定义一个名为 runoob的新全局组件 app.component('runoob', { template: '<h2>自定义组件!</h2>' }) // 定义一个名为 button-counter的新全局组件 app.component('button-counter', { data() { return { count: 0 } }, template: ` <button @click="count++"> 点了 {{ count }} 次! </button>` })
app.component('runoob', { template: '<h2>自定义组件!</h2>' }) app.mount('#app') </script>局部组件(components)
//对象const ComponentA = { /* ... */}const ComponentB = { /* ... */}
//使用const app = Vue.createApp({ components: { 'component-a': ComponentA, 'component-b': ComponentB }})对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字(component-a、component-b),其属性值就是这个组件的选项对象(ComponentA、ComponentB)。
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
定义两个局部组件
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <runoob-a></runoob-a> <runoob-b></runoob-b> </div> <script>
var runoobA = { template: '<h2>自定义组件A!</h2>' }
var runoobB = { template: '<h2>自定义组件B!</h2>' }
const app = Vue.createApp({ components: { 'runoob-a': runoobA, 'runoob-b': runoobB, } }) app.mount('#app') </script>浏览器渲染结果:
原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <runoob-a></runoob-a> <runoob-b></runoob-b> </div> <script>
var runoobA = { template: '<h2>自定义组件A!</h2>' }
var runoobB = { template: '<h2>自定义组件B!</h2>' }
const app = Vue.createApp({ components: { 'runoob-a': runoobA, 'runoob-b': runoobB, } }) app.mount('#app') </script>Prop
prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <site-name name="Muze" mail="1@1.com"></site-name> </div>
<script> const app = Vue.createApp({})
app.component('site-name', { props: ['name', 'mail'], template: `<h2>昵称:{{ name }}<br />邮箱:{{ mail }}</h2>` })
app.mount('#app') </script>浏览器渲染结果
原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。
<script src="https://unpkg.com/vue@next"></script> <div id="appa"> <site-name name="Muze" mail="1@1.com"></site-name> </div>
<script> const appA = Vue.createApp({})
appA.component('site-name', { props: ['name', 'mail'], template: `<h3>昵称:{{ name }}<br />邮箱:{{ mail }}</h3>` })
appA.mount('#appa') </script>动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
<div id="app"> <site-info v-for="site in sites" :id="site.id" :title="site.title"></site-info> </div>
<script> const Site = { data() { return { sites: [ { id: 1, title: 'Google' }, { id: 2, title: 'Runoob' }, { id: 3, title: 'Taobao' } ] } } }
const app = Vue.createApp(Site)
app.component('site-info', { props: ['id', 'title'], template: `<h4>{{ id }} - {{ title }}</h4>` })
app.mount('#app') </script>浏览器演示效果
原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。
<div id="appw"> <site-info v-for="site in sites" :id="site.id" :title="site.title"></site-info> </div>
<script> const Site = { data() { return { sites: [ { id: 1, title: 'Google' }, { id: 2, title: 'Runoob' }, { id: 3, title: 'Taobao' } ] } } }
const appW = Vue.createApp(Site)
appW.component('site-info', { props: ['id', 'title'], template: `<h4>{{ id }} - {{ title }}</h4>` })
appW.mount('#appw') </script>限制
- 类型属性:type:xx
- 必传属性:required:true
- 默认属性:default:xx
Prop 验证
组件可以为 props 指定验证要求。
为了定制 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 将会产生一个控制台的警告。
type 可以是下面原生构造器:
StringNumberBooleanArrayObjectDateFunctionSymbol
type 也可以是一个自定义构造器,使用 instanceof 检测。
例子
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <site-name name="Muze" mail="1@1.com" age="18"></site-name> </div> <script> const app = Vue.createApp({}) app.component('site-name', { props: { //昵称 "name": { type: String, //类型属性 required: true, //必传属性 default: "外星人", //默认值 }, //邮箱 "mail": { type: String, required: false, default: "myemail@email.com", }, //年龄 "age": { type: Number, required: true, default: "未知", } }, template: `<h2> 昵称:{{ name }}<br /> 邮箱:{{ mail }}<br /> 年龄:{{ age }}</h2>` }) app.mount('#app') </script>浏览器渲染
原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。
<script src="https://unpkg.com/vue@next"></script> <div id="appy"> <site-name name="Muze" mail="1@1.com" age="18"></site-name> </div> <script> const appY = Vue.createApp({}) appY.component('site-name', { props: { //昵称 "name": { type: String, //类型属性 required: true, //必传属性 default: "外星人", //默认值 }, //邮箱 "mail": { type: String, required: false, default: "myemail@email.com", }, //年龄 "age": { type: Number, required: true, default: "未知", } }, template: `<h4> 昵称:{{ name }}<br /> 邮箱:{{ mail }}<br /> 年龄:{{ age }}</h4>` }) appY.mount('#appy') </script>组件接收外部传来数据的三种方式:
(1)只接收:props: ['name','age','sex']
(2)接收并限制类型:props: { "name":Number }
(3)限制类型、限制必要性指定默认值:
props:{ "name":{ type:String, required:true }, "age":{ type:Number, default:18 }, "sex":{ type:String, default:'男' },},年龄+1 岁
<site-name name="Muze" mail="1@1.com" :age="18"></site-name>
年龄:{{ age+1 }}</h2>
做个按钮,年龄点击变 99 岁
待完善实战代码
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <h2>{{ msg }}</h2> <button @click="add">计数器:{{counte}}</button> <site-name></site-name> </div> <script> //父组件 const appRoot = { data() { return { msg: "个人基本信息", counte: 1, } }, methods: { add() { this.counte += 1; }
}, }
app = Vue.createApp(appRoot);
//子组件 app.component('site-name', { props: { //年龄 "age": { type: Number, required: true, default: "18", } },
template: `<h2>年龄:{{ age }}</h2>`, })
app.mount('#app');
</script>浏览器渲染
原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。
<script src="https://unpkg.com/vue@next"></script> <div id="appM"> <h2>{{ msg }}</h2> <button @click="add">计数器:{{counte}}</button> <site-name></site-name> </div> <script> //父组件 const appRoot = { data() { return { msg: "个人基本信息", counte: 1, } }, methods: { add() { this.counte += 1; }
}, }
appm = Vue.createApp(appRoot);
//子组件 appm.component('site-name', { props: { //年龄 "age": { type: Number, required: true, default: "18", } },
template: `<h3>年龄:{{ age }}</h3>`, })
appm.mount('#appM');
</script>