学习vue2的过程中,我基本是按照vue2官网的教程走,并且主要以实现需求为主,如果不需要深入vue2的概念,就用简单的方法去实现。
本章实现了以下功能:
1、列表渲染,v-for;
2、条件渲染,v-if;
3、自适应布局;
4、事件处理器,v-on:click;
5、data数据管理。
运行效果:vue-酷我demo
1、列表渲染,v-for;
在前面几章已经使用过几次v-for指令了,对此并不陌生,这次更新实现了排行榜列表和歌手列表,以排行榜列表为例,重温一下v-for的用法。
Bang.vue:排行榜父组件,bangList是一个数组,for in遍历出来的是一个值属性,根据MDN文档对于for in遍历的解释,通常for in用来遍历对象Object。我们需要给遍历对象指定一个key,然后把遍历出来的属性list传递给子组件。
<template> <div> <ul class="bang-ul"> <app-bang v-for="list in bangList" :key="list.id" :list="list"></app-bang> </ul> </div> </template> <script> import Bang from './template/BangList.vue' //导入排行榜列表子组件 import { bangList } from '../../static/data/data' //导入数据 export default { name: 'Bang',components: { 'app-bang': Bang },data() { return { bangList: bangList } } } </script>
BangList:排行榜列表子组件, 子组件是一个li,因为li是可点击的路由,所以使用router-link包裹,:to是绑定路由地址,然后img绑定了图片路径,在dom标签中输出使用双大括号{{list.title}},而export default是指默认导出的js代码,props表示获取从父组件传递过来的参数,至于参数验证,以后再添加。
<template> <li> <router-link :to="list.pathname"> <div class="left"> <img :src="list.url" :alt="list.title"> </div> <div class="right"> {{list.title}} </div> <i class="fa fa-angle-right"></i> </router-link> </li> </template> <script> export default { props: ['list'] } </script>
2、条件渲染,v-if;
v-if非常好用,在vue2中,你可以享受到条件语句带来的便利,虽然在react中早就有这玩意了。在歌手列表页面,我使用了v-if。
Artist.vue:歌手列表父组件,因为artist是一个Object,所以首先由Object.keys()的方式遍历出key,然后使用v-if判断singer等于不同的key时渲染不同的值到模板。如果你看代码有点晕,可以运行项目对着看。
<template> <div> <artist-list v-for="singer in Object.keys(artist)" v-if="singer === 'listOne'" :singer="artist.listOne"></artist-list> <artist-list v-for="singer in Object.keys(artist)" v-if="singer === 'listTwo'" :singer="artist.listTwo"></artist-list> <artist-list v-for="singer in Object.keys(artist)" v-if="singer === 'listThree'" :singer="artist.listThree"></artist-list> <artist-list v-for="singer in Object.keys(artist)" v-if="singer === 'listFour'" :singer="artist.listFour"></artist-list> </div> </template> <script> import SingerList from './templates/SingerList.vue' //导入歌手列表子组件 import { artist } from '../../static/data/data' //导入歌手列表数据 export default { components: { 'artist-list': SingerList },data() { return { artist: artist } } } </script>
SingeList.vue:歌手列表子组件,这个子组件的实现和排行榜的例子非常相似。
<template> <ul class="singer-ul"> <li v-for="list in singer"> <router-link :to="list.pathname">{{list.title}}</router-link> <i class="fa fa-angle-right"></i> </li> </ul> </template> <script> export default { props: ['singer'] } </script>
3、自适应布局;
如果你运行了我在github上的例子,采用不同的分辨率来看,会发现会自适应,在不同分辨率下保持同样的倍数递增或者递减,这种自适应方式和酷狗移动端的实现是一致的,但是和bootsrap的栅格响应又不一样。
采用这种自适应需要注意以下几点。
在App.vue添加media属性:这里的每一个font-size都是我用计算器计算出来的 12*比例 得到的值,而酷狗采用的是百分比 % 的方式,本质是一样的。
@media screen and (min-width: 320px) { html,body { font-size: 12px !important; } } @media screen and (min-width: 360px) { html,body { font-size: 13.5px !important; } } @media screen and (min-width: 375px) { html,body { font-size: 14px !important; } } @media screen and (min-width: 414px) { html,body { font-size: 15.5px !important; } } @media screen and (min-width: 720px) { html,body { font-size: 27px !important; } } @media screen and (min-width: 1024px) { html,body { font-size: 38.4px !important; } } @media screen and (min-width: 1080px) { html,body { font-size: 40.5px !important; } } @media screen and (min-width: 1366px) { html,body { font-size: 51px !important; } } @media screen and (min-width: 1440px) { html,body { font-size: 54px !important; } } @media screen and (min-width: 1600px) { html,body { font-size: 60px !important; } } @media screen and (min-width: 1920px) { html,body { font-size: 72px !important; } }
使用这种自适应布局,你需要将你的样式采用rem或者em的方式来替代px,具体看我代码的实现。
4、事件处理器,v-on:click;
在首页的SongList.vue中,我写了个绑定事件处理器做测试。
首先,你需要在 methods 中定义方法,我定义了reverseMsg(title){}用来打印当然点击列表的值。
接着,把写好的方法用v-on:click="reverseMsg(song.title)"绑定到li上,这样你就能获取当然点击对象的值,而不需要纠结用this来获取当前点击的dom对象了。
<template> <li v-if="seen" v-on:click="reverseMsg(song.title)"> <span class="title" :title="song.singer">{{song.singer}} - {{song.title}}</span> <i :style="{background: 'url('+ downLoadIcon +') no-repeat'}"></i> </li> </template> <script> import downLoadIcon from '../../../static/outImg' export default { props: ['song'],data() { return { downLoadIcon: downLoadIcon,seen: true } },methods: { reverseMsg(title) { console.log('title: ',title) } } } </script>
5、data数据管理。
目前静态数据管理分为2大块,图片管理和静态渲染数据管理,他们都保存在static文件夹里面。
图片管理:
你可以这样写,把所有需要导出的图片放到一个js文件里面,使用module.exports的方式定义导出的文件名。
// 引用图片路径 let a = require('./img/home/banner1.png') let b = require('./img/home/banner2.jpg') let c = require('./img/home/banner3.jpg') let d = require('./img/home/banner4.jpg') let e = require('./img/home/banner5.jpg') let downLoadIcon = require('./img/home/download_icon.png') let bang1 = require('./img/bang/bang1.png') let bang2 = require('./img/bang/bang2.png') let bang3 = require('./img/bang/bang3.png') let bang4 = require('./img/bang/bang4.png') let bang5 = require('./img/bang/bang5.png') let bang6 = require('./img/bang/bang6.png') let bang7 = require('./img/bang/bang7.png') let bang8 = require('./img/bang/bang8.png') let bang9 = require('./img/bang/bang9.png') let bang10 = require('./img/bang/bang10.png') // 导出图片 module.exports = { a,b,c,d,e,downLoadIcon,bang1,bang2,bang3,bang4,bang5,bang6,bang7,bang8,bang9,bang10 }
在项目中引用图片。
import { bang1,bang10 } from '../outImg'
静态数据管理:
和图片管理的方式一样,也是通过module.exports的方式。
/ 新歌列表 const songList = [ {_id: 'songs_CC156F3A7186FB12768B2C1B48FDAA74',singer: '庄心妍',title: '屋檐下的浪漫'},{_id: 'songs_9AA99B44B77C50737A42E921EF51C937',singer: '童可可',title: '薛定谔的猫'},{_id: 'songs_9154AD94E915A6A6CDD6AF57EEFE06A6',singer: '阿杜',title: '一诺千年'},{_id: 'songs_53C3F2DBE2790BE8884E6D8F5553FE50',singer: '黄子韬',title: 'Promise'},{_id: 'songs_39224F3C618C955352142DB989737B9D',singer: '刘恺威、蒋欣',title: '明明爱【继承人插曲】'},{_id: 'songs_2B0BAE72AFC013419B2D21D86C0BA515',singer: '林忆莲',title: '我不能忘记你【记忆大师记忆主题曲】'},{_id: 'songs_A350CE1A5B0769D3E39C311C933F1234',singer: '高夫',title: '青春去哪了'},{_id: 'songs_5184FAAD32883D73533714BACAA98A1F',singer: '华晨宇',title: ' 寻【花儿与少年3·冒险季主题曲】'},{_id: 'songs_7A5B2CC635273C4B81167F19E8897773',singer: '鹏泊',title: '春来鸟'},{_id: 'songs_4BCA5B307683B83A6BC2F34A93E7DBC2',singer: '阿兰',title: '兰之乐光'},{_id: 'songs_76448B8D90609F4657782A2F4ACE3C1C',singer: '星月组合',title: '今夜的你又在和谁约会'} ] // 排行榜 const bangList = [ {url: bang1,title: '酷狗飙升榜',pathname: ''},{url: bang2,title: '酷狗TOP500',{url: bang3,title: '网络红歌榜',{url: bang4,title: 'DJ热歌榜',{url: bang5,title: '华语新歌榜',{url: bang6,title: '欧美新歌榜',{url: bang7,title: '韩国新歌榜',{url: bang8,title: '日本新歌榜',{url: bang9,title: '粤语新歌榜',{url: bang10,title: '原创音乐榜',pathname: ''} ] // 歌手 const artist = { 'listOne': [ {pathname: '',title: '热门歌手'} ],'listTwo': [ {pathname: '',title: '华语男歌手'},{pathname: '',title: '华语女歌手'},title: '华语组合'},],'listThree': [ {pathname: '',title: '日韩男歌手'},title: '日韩女歌手'},title: '日韩组合'},'listFour': [ {pathname: '',title: '欧美男歌手'},title: '欧美女歌手'},title: '欧美组合'} ] } module.exports = { songList,bangList,artist }
哎,这就是没有构建mock server的办法,不过哪些数据需要mock server呢?显然我现在使用的都是静态数据,是不需要mock来实现的。
==================================分割线============================================
这一天我把vue2官网的基础篇看了几遍,也运用了部分功能到项目中,其实生命周期在轮播图那章就已经涉及到了,只不过我没有细说,后面会挑出一章专门讲生命周期每个时间点的实际用途。
这次还更新了很多细微的东西,就不细说了,从项目中慢慢体会,打铁还需自身硬,多看看vue2官网的教程,会更有启发。
项目地址:https://github.com/hyy1115/vu... (对你学习vue2有帮助的话,别吝啬给个star支持一下)