此文章,是我在看vue教程时整理的组件部分知识,其中包括网上找的一些案例,有转载意思,只是我进行了编译,如有维权,请联系。
1.组件分为全局注册和局部注册
全局组件注册:必须在new之前注册。
局部组件注册:可以在作用域内使用componentsd
data 必须是函数
报错:
<body> <div id="app"> <my-component></my-component> </div> <script> Vue.component('my-component', { template: '<span>{{ message }}</span>', data:function() { message: 'hello' } }) var vm = new Vue({ el:'#app' }) </script> </body>
[Vue warn]: Property or method "message" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
found in
---> <MyComponent>
<Root>
VU.M.JS:435(VUE警告):属性或方法“消息”不是在实例上定义的,而是在渲染期间引用的。请确保在数据选项中声明无功数据属性。
修改成
<div id="app"> <my-component></my-component> </div> <script> Vue.component('my-component', { template: '<span>{{ message }}</span>', data:function() { return{ message: 'hello' } } }) var vm = new Vue({ el:'#app' }) </script>
或者:
<div id="app"> <my-component></my-component> </div> <script> var x = { message: 'hello' } Vue.component('my-component', { template: '<span>{{ message }}</span>', data:function() { return x } }) var vm = new Vue({ el:'#app' }) </script>
什么是prop(支柱)
实际就是,你自定义的标签属性,想传递给替换标签时,使用。
<body> <div id="app"> <blog-post title="my name is dinghongli"></blog-post> <blog-post title="my name is dingxiang"></blog-post> <blog-post title="my name is dingleiying"></blog-post> </div> <script> Vue.component('blog-post',{ template:'<h3>{{ title }}</h3>', props:['title'] }) new Vue({ el:'#app' }) </script> </body>
<body> <div id="app"> <blog-post v-for="post in posts" v-bind:key = 'post.id' v-bind:title = "post.title" ></blog-post> </div> <script> Vue.component('blog-post',{ template:'<h3>{{ title }}</h3>', props:['title'] }) new Vue({ el:'#app', data:{ posts:[ { id:1, title:'my name is dinghongli'}, { id:2, title:'my name is dingxiang'}, { id:3, title:'my name is dingleiying'} ] } }) </script> </body>
在组件上使用 v-model
<body> <div id="blog-posts-events-demo"> <custom-input v-bind:value="searchText" v-on:input="searchText = $event" ></custom-input> </div> <script> Vue.component('custom-input', { props: ['value'], template: ` <input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > ` }) new Vue({ el: '#blog-posts-events-demo', data:{ searchText:'dfksjfksfj' } }) </script> </body>
通过插槽分发内容
<body>
<div id="app">
<alert-box> fdkjfsjfskfjskfjkfjkf </alert-box>
</div>
<script>
Vue.component('alert-box',{
template:`<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>`
})
new Vue({
el:'#app'
})
</script>
</body>
动态组件
让多个组件使用同一个挂载点,并动态切换,这就是动态组件。
通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,可以实现动态组件
<body>
<div id="example">
<button @click="change">切换页面</button>
<component v-bind:is="currentView"></component>
</div>
<script>
var home = { template:'<div>我是主页</div>'};
var post = { template:'<div>我是提交页</div>'};
var archive = { template:'<div>我是存档页</div>'};
new Vue({
el:'#example',
components:{
home,
post,
archive
},
data:{
index:0,
arr:['home','post','archive']
},
computed:{
currentView:function(){
return this.arr[this.index];
}
},
methods:{
change:function(){
this.index = (++this.index)%3;
}
}
})
</script>
</body>
直接绑定到组件对象上
<body>
<div id="example">
<button @click="change">切换页面</button>
<component :is="currentView"></component>
</div>
<script>
new Vue({
el: '#example',
data:{
index:0,
arr:[
{template:`<div>我是主页</div>`},
{template:`<div>我是提交页</div>`},
{template:`<div>我是存档页</div>`}
],
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
this.index = (++this.index)%3;
}
}
})
</script>
解析DOM模板时的注意事项
固定的标签结构,需用is特性来标识
<body>
<div id="app">
<table>
<tr is="my-row"></tr>
</table>
</div>
<script>
Vue.component('myRow', {
template: '<tr>行元素</tr>'
});
new Vue({
el: '#app'
});
</script>
</body>
组件注册
1.1组件名大小写
驼峰命名,要在标签里替换成短横杠命名
<body>
<div id="app">
<my-component-name></my-component-name>
</div>
<script>
Vue.component('myComponentName',{
template:'<div>哈哈哈哈哈哈哈</div>'
})
new Vue({
el: '#app'
});
</script>
</body>
全局组件注册:必须在new之前注册。
局部组件注册:可以在作用域内使用components 对于 components 对象中的每个属性来说,其属性名就是自定义元素的名
<body> <div id="app"> <component-a></component-a> <component-b></component-b> <component-c></component-c> </div> <script> var componentA = { template:'<div>你好</div>'}; var componentB = { template:'<div>哈哈</div>'}; var componentC = { template:'<div>嘿嘿</div>'}; new Vue({ el: '#app', components:{ 'component-a':componentA, 'component-b':componentB, 'component-c':componentC } }); </script> </body>
注意局部注册的组件在其子组件中不可用。例如,如果你希望
ComponentA
在
ComponentB
中可用,则你需要这样写:
var ComponentA = { /* ... */ } var ComponentB = { components: { 'component-a': ComponentA },
// ...
}传入一个对象的所有属性
<body> <div id="app"> <blog-post v-bind ="info"></blog-post> </div> <script> Vue.component('blog-post',{ props:['vBind'], template:'<div>{{ vBind }}</div>' }) new Vue({ el: '#app', data:{ post: { id: 1, likes: 'My Journey with Vue', currentUserFavorited:false, favorited:'', commentIds:'dinghongli' }, info:{ id: 1, title: 'My Journey with Vue' } } }); </script> </body>
vue.js将一个对象的所有属性作为prop进行传递
1.方法一:使用不带参数的v-bind写 :v-bind中没有参数,而组件中的props需要声明对象的每个属性
<body> <div id="app"> <child v-bind="todo"></child> </div> <script> Vue.component('child', { props: ['text','isComplete'], template: '<span >{{ text }} {{isComplete}}</span>' }) new Vue({ el: '#app', data: { todo: { text: 'Learn Vue', isComplete: false } } }) </script> </body>
2.方法二:使用带参数的v-bind写法
v-bind后跟随参数todo,组件中的props需要声明该参数,组件变可以通过todo来访问对象的属性
<body> <div id="app"> <child v-bind:todo = "todo" ></child> </div> <script> Vue.component('child', { props: ['todo'], template: '<span >{{ todo.text }}{{ todo.isComplete }}</span>' }) new Vue({ el: '#app', data: { todo: { text: 'Learn Vue', isComplete: false } } ) </script> </body>
prop验证
<body> <div id="app"> <my-child :num = "100" :msg = "'sdf'" :object = "{a:'a'}" :cust = "100" ></my-child> </div> <script> Vue.component('my-child',{ props:{ num: Number, propB: [String,Number], msg:{ type:String, required:true }, num1:{ type:Number, default: 1000 }, object:{ type:Object, default:function(){ return { message:'hello' } } }, cust:{ validator:function (value){ return value > 10 } } }, template:`<div> <p>{{ num }}</p> <p>{{ msg }}</p> <p>{{ num1 }}</p> <p>{{ object }}</p> <p>{{ cust }}</p> ` }) new Vue({ el:'#app' }) </script> </body>
替换合并己有的特性
class 和 style 会合并,class 和 style 特性会稍微智能一些,即两边的值会被合并起来,
<body> <div id="app"> <bootstrap-date-input data-date-picker="activated" class="date-picker-theme-dark" ></bootstrap-date-input> </div> <script> Vue.component('bootstrap-date-input',{ template:'<input type="date" class="form-control">', props:[''] }) new Vue({ el:'#app' }) </script> </body>
结果:
禁用特性继承 (无案例)
自定义事件
自定义事件的主要作用是,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 也就是相互通知
这里推荐 :https://blog.csdn.net/hayre/article/details/60572435 讲的很明白。
<body> <div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> <script> Vue.component('button-counter', { template: '<button v-on:click="increment">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { increment: function () { this.counter += 1 this.$emit('increment') } } }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } }) </script> </body>
自定义组件的v-model
转载自:https://www.cnblogs.com/bldf/p/6645225.html
<input v-model="something">
v-model指令其实是下面的语法糖包装而成:
<input :value="something" @:input="something = $event.target.value">
在一个组件上使用 v-model 时,会简化为:
<custom-input :value="something" @input="value => { something = value }"> </custom-input>
因此,对于一个带有 v-model 的组件,它应该如下:
- 接收一个
valueprop - 触发
input事件,并传入新值
利用 $emit 触发 input 事件:
this.$emit('input', value);组件1:
Vue.component('my-component', {
template: `<div>
<input type="text" :value="currentValue" @input="handleInput"/>
</div>`,
data: function () {
return {
currentValue: this.value
}
},
props: ['value'], //接收一个 value prop
methods: {
handleInput(event) {
var value = event.target.value;
this.$emit('input', value); //触发 input 事件,并传入新值
}
}
});
currentValue: this.value 上面是将prop属性绑定到data里,以便修改 prop 数据(Vue不允许直接修改prop属性的值)#查看原理#
组件2:
Vue.component("my-counter", {
template: `<div>
<h1>{{value}}</h1>
<button @click="plus">+</button>
<button @click="minu">-</button>
</div>`,
props: {
value: Number //接收一个 value prop
},
data: function() {
return {
val: this.value
}
},
methods: {
plus() {
this.val = this.val + 1
this.$emit('input', this.val) //触发 input 事件,并传入新值
},
minu() {
if(this.val>0){
this.val = this.val-1
this.$emit('input', this.val) //触发 input 事件,并传入新值
}
}
}
});
<body> <div id="app"> <!-- <price-input v-model="price"></price-input> --> <!-- 手动实现了v-model双向绑定 --> <!-- 3、父组件的input事件被触发,将传来的值赋给父组件的变量price --> <!-- 4、父组件value的值绑定到price --> <price-input :value="price" @input="onInput"></price-input> <p>{{price}}</p> </div> <script> Vue.component('price-input', { // 5、将父组件的value值通过props传递给子组件 // 1、当有数据输入时触发了该组件的input事件 template: '<input :value="value" @input="updateVal($event.target.value)" type="text">', props: ["value"], methods: { updateVal: function(val) { // 2、手动触发父组件的input事件并将值传给父组件 this.$emit('input', val); } } }); var app = new Vue({ el: '#app', data: { rice: '' }, methods: { onInput: function(val) { this.price = val; } } }); </script> </body>
将原生事件绑定到组件上,使用native修饰符
我们引入一个原生标签(div、li、p......)的概念,那么原生事件(存在于标准当中的如'click', 'mouseover')应该绑定到原生标签上。自定义组件上应该绑定自定义事件。
如果我们想给自定义组件标签(注意是标签,不是内部元素)绑定原生事件(使原生事件生效于组件template的root element上)怎么办,加.native修饰符。
<body>
<div id="app">
<my-ding @click.native = "doThis"></my-ding>
<div @click = 'doThis'>你好吗???</div>
</div>
<script>
Vue.component('my-ding',{
template:'<div>开心每一天</div>'
});
new Vue({
el:'#app',
methods:{
doThis:function(){
console.log('我是丁红丽')
}
}
})
</script>
</body>
.sync修饰符
<body>
<div id="app">
<div>{{bar}}</div>
<my-comp :foo.sync="bar"></my-comp>
<!-- <my-comp :foo="bar" @update:foo="val => bar = val"></my-comp> -->
</div>
<script>
Vue.component('my-comp', {
template: '<div @click="increment">点我+1</div>',
data: function() {
return {copyFoo: this.foo}
},
props: ['foo'],
methods: {
increment: function() {
this.$emit('update:foo', ++this.copyFoo);
}
}
});
new Vue({
el: '#app',
data: {bar: 0}
});
</script>
</body>