Vue 第三天
练习
第二天学了路由配置、编写按钮组件和按钮的点击事件。
先练习一遍~
按钮自定义点击事件
昨天写的按钮的点击事件中,将按钮事件写成了默认的 alert(this.msg)
,如果有些按钮想要异化,按钮的点击事件也是支持自定义的。
pageQuiButton.vue
:
//监听子组件的事件(子组件:quiButton.vue)
<qui-btn v-on:btnClickEvent="doSth" msg="我可以点击"></qui-btn>
上述代码在引用组件的时候,注册了一个事件,这个btnClickEvent是之前我们在 quiButton.vue
中绑定按钮的click事件,然后我们给这个事件一个自定义的方法doSth,同时在script标签中声明这个自定义方法:
//页面中引用子组件并监听子组件的事件
<script>
import quiBtn from '../components/quiButton.vue'
export default {
name: 'pageQuiButton',
components: {
'qui-btn': quiBtn /* 注册自定义标签 */
},
methods: {
doSth:function (){
alert('你点击了组件的click:btnClickEvent');
}
}
}
</script>
这种做法专业来说叫做监听,由父组件(也就是引用方)监听子组件的内置方法,同时在子组件中,需要触发这个事件:
quiButton.vue
:
//子组件中代码
<script>
export default{
props:{
msg:{
default:'下载'
}
},
methods:{ //绑定点击事件
btnClickEvent: function(){
alert('先弹出默认文案');
this.$emit('btnClickEvent'); //此为关键代码,父组件触发自定义事件
}
}
}
</script>
上述代码中 $emit
就是关键代码,也叫触发机制,父组件监听,子组件触发。
学会了这招后,引用方就可以给不同的子组件调用不同的事件处理了:
pageQuiButton.vue
:
<template>
<div id="pageQuiButton">
<qui-button v-on:btnClickEvent="doSth" msg="我可以点击" ></qui-button>
<qui-button v-on:btnClickEvent="doSth1" msg="确定"></qui-button>
<qui-button v-on:btnClickEvent="doSth2" msg="取消"></qui-button>
</div>
</template>
<script>
import quiBtn from '../components/quiButton.vue'
export default {
name: 'pageQuiButton',
components: {
'qui-button': quiBtn /* 注册自定义标签 */
},
methods:{
doSth:function () {
alert('你点击了组件的click:btnClickEvent');
},
doSth1:function () {
alert("你点击了确定按钮");
},
doSth2:function () {
alert("你点击了取消按钮");
}
}
}
</script>
给按钮加图标
一般特殊按钮,比如 收藏
、 下载
按钮都是图标+文字类型的,而且图标还可能不一样,所以vue提供了 slot
标签:
quiButton.vue
:
<template>
<button class="qui-btn" @click="btnClickEvent">
<slot name="icon"></slot> <!--加图标-->
<span> { { msg}} </span>
</button>
</template>
上述代码中,加入了关键字 solt
标签并赋予了一个name值,然后我们就可以在父组件中引用了:
pageQuiButton.vue
<qui-button v-on:btnClickEvent="doSth3" msg="下载" class="with-icon">
<img slot="icon" class="ico" src="http://qzonestyle.gtimg.cn/aoi/sola/20170214175951_TA6qW1X7ob.png">
</qui-button>
上述代码中,img
标签中有个关键字 slot="icon"
,对应子组件中 slot
标签中 name="icon"
,会将img整个替换掉组件中的对应name的 slot
标签,slot翻译后的意思是 插槽,相当于把 img
这块的内容插到一个name为 icon
的插槽中去
script标签中:
<script>
//....省略前面的代码
doSth3:function(){
alert("你点击了下载按钮,下载中....")
}
</script>
我们可以看到页面效果:
接下来学习一下Vue中对于for循环的巧妙使用:
导航组件quiNav.vue
在现实项目中,导航的tab个数是不定的,所以制作组件的时候,可以暴露一个属性来支持导航的tab个数,而tab的长相和应用其实是一样的,这时候可以用一个for循环来输出每一个tab。
<template>
<div class="qui-nav nav-type-1">
<a v-for="(item, index) in items"> <!--关键代码 v-for-->
<span class="nav-txt"> { { item.text}} </span>
</a>
</div>
</template>
<script>
export default {
data: function () {
return {
items: [
{
text: '首页',
active: true
},
{
text: '列表',
active: false
},
{
text: '关于',
active: false
},
{
text: '招聘',
active: false
}
]
}
}
}
</script>
<style scoped>
@import './css/reset.import.css';
@import './css/qui-nav.import.css';
</style>
上述代码的关键地方在于a标签上 v-for
关键字,可以把它理解为js中的 for in 循环,items使我们在data里面定义的对象。v-for="(item,index) in items"
暴露了item 和 index两个接口,这是Vue提供的,代表items中的每一项以及该项对应的下标,然后我们就可以在标签中使用绑定 { {item.text}}
了。
再延伸一个动态添加class的概念,我们希望每个tab都有默认的class类名(比如 nav-item
类),在点击每个tab的时候,当前tab添加active类,其他的tab删除这个tab类。
动态类名
quiNav.vue
:
<template>
<div class="qui-nav nav-type-1">
<a v-for="(item, index) in items" :class="[commonClass,item.active ? activeClass : '']" >
<span class="nav-txt">{ { item.text}}</span>
</a>
</div>
</template>
<script>
export default {
data:function(){
return {
commonClass:'nav-item',
activeClass:'active',
items:[
...//数据
]
}
}
}
</script>
在template中添加了一句关键代码:
:class="[commonClass,item.active ? activeClass : '']"
:class
给组件绑定一个class属性,这里是缩写,它的全拼是v-bind: ,最前面有个冒号,**:class=XXX
和 class=XXX
的区别在于不带冒号的是静态的字符串绑定,带冒号的是动态的变量绑定 **。
我们给class绑定了一个数组,这个数组带有变量,先看commonClass,这个变量在data中定义了,然后数组的第二个元素是一个js的三元运算符: item.active ? activeClass : ''
,当每个item中的active值为true时,绑定activeClass变量对应的类,如果为false,则为空。
结果就是当item.active的值为true时,tab的class值为 nav-item active
,当为false,就只有 nav-item
。
我们切换tab的active类,就转换为修改每个item里面的active的值(数据驱动)。给每个tab绑定一个点击事件,当点击事件触发的时候,修改当前tab对应item的active值。
quiNav.vue
:
<template>
<div class="qui-nav nav-type-1">
<a v-for="(item, index) in items" :class="[commonClass,item.active ? activeClass : '']" v-on:click="navClickEvent(items,index)" >
<span class="nav-txt">{ { item.text}}</span>
</a>
</div>
</template>
<script>
export default {
data:function(){
return {
commonClass:'nav-item',
activeClass:'active',
items:[
{
text: '首页',
active : true
},
......
]
}
},
methods:{
navClickEvent:function(items,index){
/*默认切换类的动作*/
items.forEach(function(el){
el.active = false;
});
items[index].active = true;
/*开放用户自定义的接口*/
this.$emit('navClickEvent',items,index);
}
}
}
</script>
利用for循环给每个a标签绑定了一个click事件,对应methods中定义的navClickEvent,接收两个参数 items 和 index(也可以传入 item 和 index),然后当点击的时候,把items中的每个item.active置为false,把当前的tab的active值置为true,这样就可以动态切换active类了。最后再触发一次自定义事件(同按钮制作自定义事件)。
pageQuiNav.vue
:
//index.vue
<template>
<div id="pageQuiNav">
<qui-nav v-on:navClickEvent="dosth"></qui-nav>
</div>
</template>
<script>
import quiNav from '../components/quiNav.vue'
export default {
name: 'pageQuiNav',
components: {
'qui-nav': quiNav
},
methods:{
dosth:function(items,index){
console.log(items[index].text + index);
}
}
}
</script>
<style scoped>
</style>
别忘了配置路由,否则看不到效果哦!
src/router/index.js
:
import Vue from 'vue'
import Router from 'vue-router'
import index from '../pages/index'
import pageQuiButton from "../pages/pageQuiButton";
import pageQuiNav from "../pages/pageQuiNav"
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'index',
component: index
},
{
path: '/btn',
name: 'btn',
component: pageQuiButton
},
{
path: '/nav',
name: 'nav',
component: pageQuiNav
},
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
页面效果:
回顾
for循环输出每个tab,为每个tab绑定动态的class类名,同时在点击事件中动态切换类(底部的小黄条其实就是利用active类做的css)
总结
- 按钮组件自定义事件 $emit
- 按钮组件自定义子块slot
- for循环实现导航组件
- 动态类名