[TOC]javascript
组件的特色:vue
无需单独引用或配置,直接在大组件中调取全局组件便可java
语法:
Vue.component(component.name,options)
node
component.name
组件命名的规则
调取组件的时候,会把因此组件的单词渲染为小写字母**(咱们命名的时候除PasalCase模式外,咱们都要把组件名设置为小写,调取组件的时候能够是大写也能够是小写(最后都是按照小写渲染 ))vuex
命名的时候尽可能不要出现其他的特殊字符数组
options
可使用的有VM实例具备的一切(DATA,METHODS,生命周期函数)每调用一次组件都是建立一个单独的VUE实例(VueComponent--->vue)浏览器
<body>
<div id="app"> <h3 v-text='title'></h3> // <my-button/> //单闭合:不符合w3c规范,调取完成后,后面的视图不识别(避免使用) //双闭合:能够设置除组件规定内容外的其他内容(slot插槽) <my-button> 我加的其它内容(slot 插槽) //没有效果,须要使用slot插槽 </my-button> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> Vue.component('MyButton', { template: `<button>组件中的按钮</button>` }); let vm = new Vue({ el: '#app', data: { title: '你们好哇~' } }); </script> </body>
复制代码
把调取组件时候,写在组件中间部分的内容获取到,放置到组件的某个位置(具体位置根据需求来),依托这种方式,可让当前组件具有更强的扩展性闭包
/* * 必须设置template或者render函数:来规定当前组件的渲染视图 * 1.只能有一个根元素节点 * 2.template的值能够是字符串(包裹须要的结构),也能够把结构单独分离出来,放置到<template></template>标记中,而后和当前组件关联 * DATA必须是一个函数:至关于造成一个闭包,让返回的对象(须要的响应式数据)是当前实例的私有的 */
<body>
<div id="app"> <h3 v-text='msg'></h3> <!-- 调用组件 --> <my-app> <template v-slot:before><p>我是调取组件的时候,在组件模板外单独写的内容</p></template> <template #after><p>我是后面的</p></template> </my-app> </div> <!-- TMPLATE:建立TMPLATE标签用来构建组件渲染的视图 --> <template id="mybutton"> <div> <slot name='before'></slot> <button @click='handle'>我是template组件{{msg}}</button> <slot name='after'></slot> </div> </template> <script src="./node_modules/vue/dist/vue.js"></script> <script> Vue.component('MyApp', { template: '#mybutton', data() { return { msg: '你好哇~' } }, methods: { handle() { this.msg = '~hello world~' } } }) let vm = new Vue({ el: '#app', data: { msg: 'hello~' } }); </script> </body>
复制代码
建立组件:let componenName={...}app
基于components属性声明组件:想用哪一个组件须要先声明函数
使用组件
<body>
<div id="app"> <my-button></my-button> </div> <!-- 建立 template 标签来构建组件渲染视图--> <template id="MyButtonTemplate"> <div> <button>组件按钮~{{msg}}</button> <p>哈哈哈</p> </div> </template> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 1. 建立局部组件 const MyButton = { template:'#MyButtonTemplate', data(){ return{ msg:'hello~' } } }; let vm = new Vue({ el: '#app', /2. 注册当前视图中须要使用的局部组件 components:{ MyButton } }) </script> </body>
复制代码
<my-component title='哈哈哈' :data-index='0'></my-component> //传递的属性值默认都是字符串格式,若是想要让传递的值是数字、布尔、数组、对象等格式,咱们须要使用v-bind处理 复制代码
Vue.component('my-component',{
props:['title','dataIndex'],
...
})
/* props中声明的属性和data同样,是响应式数据,挂载到vm实例上,可控制视图渲染 * 命名大小写:父组件传递的是kebab-case格式,props中获取的是camelCase驼峰命名|pasalCase * 基于属性传递进来的值,只能获取使用,不能在子组件中修改(修改后会有对应的效果,子组件会从新渲染,可是控制台会报错) */
复制代码
/* 指定属性的类型:props:{xxx:String,...} * 指定属性的默认值:props:{xxx:{type:String,default:'xxx',required:true}} - type若是是一个数组,意为指定的多类型皆能够 - default能够是一个函数,函数返回值是默认值 - validator自定义验证规则函数:必须符合函数中指定的规则,返回true/false */
props: {
//=>指定属性的类型
props: {
title: String,
dataIndex: [Number, Array]
},
//=>设置默认值
title: {
type: String,
default: '我是设定的属性默认值'
},
aaa: {
//=>数据格式
type: [Number, Array],
//=>是否为必传 TRUE必须传递
required: true
//=>自定义验证规则 val传递的属性值 在函数中,根据本身的规则,返回TRUE和FALSE来验证传递的值是否符合规则
validator(val) {
return val >= 0;
}
}
},
复制代码
样式和class自动合并问题
能够把子组件当作一个标签,咱们能够设置ID/CLASS/STYLE等内置属性值,这些属性也会传递给子组件,VUE帮咱们处理好的,该合并的合并,该覆盖的覆盖,无需咱们在PROPS中注册处理
全部的 prop 都使得其父子 prop 之间造成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,可是反过来则不行。
Vue 的父组件和子组件生命周期钩子函数执行顺序能够归类为如下 4 部分:
加载渲染过程:父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子组件更新过程:父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父组件更新过程:父 beforeUpdate -> 父 updated
销毁过程:父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
每次父级组件发生更新时,子组件中全部的 prop 都将会刷新为最新的值。这意味着你不该该在一个子组件内部改变 prop。若是你这样作了,Vue 会在浏览器的控制台中发出警告。
子组件想修改时,只能经过
$emit
派发一个自定义事件,父组件接收到后,由父组件修改。有两种常见的试图改变一个 prop 的情形 :这个 prop 用来传递一个初始值;这个子组件接下来但愿将其做为一个本地的 prop 数据来使用。 在这种状况下,最好定义一个本地的 data 属性并将这个 prop 用做其初始值
这个 prop 以一种原始的值传入且须要进行转换。 在这种状况下,最好使用这个 prop 的值来定义一个计算属性
订阅自定义事件:调用组件的时候基于属性传递一个方法 (父)
<my-component @func='xxx'></my-component> new Vue({ methods:{ xxx(value){ //=>value是this.$emit时候传递的第二个参数值 } } }); 复制代码
通知自定义事件执行 (子)
{
methods:{
xxx(){
this.$emit('func',10);
}
}
}
复制代码
let eventBus = new Vue; //=>建立事件总线
//A组件 => 基于$on建立一个自定义事件:把指定方法放到任务队列中(兄弟)
eventBus.$on('xxxA',this.func);
//B组件=> 通知自定义事件执行
eventBus.$emit('xxxA');
复制代码
经过this.$children 控制子组件的显示隐藏
<body>
<div id="app"> <my-vote v-for='item in voteList' :title="item.title"></my-vote> </div> <!-- TEMPLATE --> <template id="MyVoteTemplate"> <div class="container"> <h3> <span v-text='title'></span> (<span v-text='num'></span>) <button type="button" class="btn btn-primary" @click='handle'>点着玩</button> </h3> <vote-button ref='button'></vote-button> </div> </template> <template id="VoteButtonTemplate"> <div class="footer" v-show='flag'> <button type="button" class="btn btn-primary" @click="handle('support')">支持</button> <button type="button" class="btn btn-danger" @click="handle('oppose')">反对</button> </div> </template> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> const VoteButton = { template: '#VoteButtonTemplate', methods: { handle(type) { // console.log(this.$parent); this.$parent.num++; } }, data() { return { flag: true } } }; const MyVote = { template: '#MyVoteTemplate', props: ["title"], data() { return { num: 0 } }, components: { VoteButton }, methods: { handle() { // console.log(this.$children); // this.$children[0].flag = !this.$children[0].flag; this.$refs.button.flag = !this.$refs.button.flag; } } }; let vm = new Vue({ el: '#app', data: { voteList: [{ id: 1, title: '哈哈哈' }, { id: 2, title: '呵呵呵' }] }, components: { MyVote } }); // vuex:公共状态管理 </script> </body> 复制代码
<body>
<div id="app">
<my-vote v-for='item in voteList' :title="item.title"></my-vote>
</div>
<!-- TMPLATE:建立TMPLATE标签用来构建组件渲染的视图 -->
<template id="myVoteTemplate">
<div class="container">
<h3><span v-text='title'></span>(<span v-text='num'></span>)</h3>
<my-content :eventbus='eventBus'></my-content>
<!-- 2.于自定义事件,把父组件的某个方法注册到任务队列当中 -->
<my-button @changeparent='changeParent' :eventbus='eventBus'></my-button>
</div>
</template>
<template id="myContentTemplate">
<div class="content">
<p>支持人数:<span v-text='supNum'></span></p>
<p>反对人数:<span v-text='oppNum'></span></p>
<p>支持率:<span v-text='ratio'></span></p>
</div>
</template>
<template id="myButtonTemplate">
<div class="footer">
<button type="button" class="btn btn-success" @click="handle('support')">支持</button>
<button type="button" class="btn btn-danger" @click="handle('oppose')">反对</button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
/* 1. 点击子组件影响父组件的数据
*/
// let eventBus = new Vue;
const myContent = {
template: '#myContentTemplate',
props: ['eventbus'],
data() {
return {
supNum: 0,
oppNum: 0
}
},
computed: {
ratio() {
let total = this.supNum + this.oppNum;
if (total === 0) {
return '0%';
}
return (this.supNum / total * 100).toFixed(2) + '%'
}
},
methods: {
// 1. 建立一个方法(兄弟)
changeNum(type) {
type === 'support' ? this.supNum++ : this.oppNum++;
}
},
created() {
// 2.基于$on建立一个自定义事件:把指定方法放到任务队列中(兄弟)
this.eventbus.$on('changesupport', this.changeNum)
}
}
const myButton = {
template: '#myButtonTemplate',
props: ['eventbus'],
data() {
return {}
},
methods: {
handle(type) {
// 3.通知任务队列中changeParent这个事件执行
// 事件类型,后面的参数都是通知方法执行的时候,给方法传递的参数
this.$emit('changeparent', type);
// 3.点击执行handle时,通知自定义事件执行;
this.eventbus.$emit('changesupport', type);
}
}
}
const myVote = {
template: '#myVoteTemplate',
data() {
return {
num: 0,
eventBus: new Vue
}
},
props: ['title'],
components: {
myContent,
myButton
},
//1. 自定义事件(子改父)
methods: {
changeParent(type) {
this.num++;
}
}
}
let vm = new Vue({
el: '#app',
data: {
voteList: [{
id: 1,
title: '今每天气很好~'
},
{
id: 2,
title: '今每天气很差~'
},
{
id: 3,
title: '今每天气还能够~'
}]
},
components: {
myVote
}
})
</script>
</body>
复制代码