按照国际惯例先放效果图
项目结构搭建
首先修改app.vue
<template> <div id="app"> <router-view/> </div> </template> <script> export default { name: 'App' } </script> <style> *{ margin:0; padding: 0; list-style:none; } </style>
修改main.js,引入rem公式文件
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import './config/rem' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
在src文件夹下,创建文件夹config,新建文件rem.js
(function(){function a(){var b=document.documentElement.clientWidth;b=b>750?750:b;var c=b/750*100;document.getElementsByTagName("html")[0].style.fontSize=c+"px"}a();window.onresize=a})();
这个代码可以去网上找,有很多,效果都一样,实现方法也差不太多
修改router/index.js 路由文件
浏览器访问:
移动端项目配置:
在根目录下的index.html中添加移动端meta头
安装px移动转换为rem单位的插件
cnpm install px2rem-loader --save-dev
(安装依赖,最好是加上--save-dev,否则重启的时候需要再次安装)
在build文件夹下的utils.js中配置:
remUnit设置原理:
如果设计稿给的是375,就在调试工具375页面下查看html元素的font-size
显示是50,那么就设置50
如果给的设计稿是750,那么就调到750尺寸下,查看html的font-size,来设置remUnit
然后重启项目即可生效
在detail.vue中设置宽度单位为px作为测试
浏览器里观察到单位自动转换为了rem
不想要转为rem单位的,就在后面加上/*no*/
效果
sketch设计稿介绍:
布局一般都是有设计稿的,mac推荐sketch
windows就pxcook或者photoshop,如果想体验sketch,可以在windows上装mac虚拟机(这个我晚上研究研究再发一篇博)
修改项目总体样式 app.vue
<template> <div id="app"> <router-view/> </div> </template> <script> export default { name: 'App' } </script> <style> *{ margin:0; padding: 0; list-style:none; } a{ text-decoration: none; color:#333; } </style>
components组件:
共用的组件一般都作为组件来实现
头部组件
创建header文件夹下的index.vue,放代码
<template> <div class="c-header"> <ul class="header-ul"> <li>推荐</li> <li>课程</li> <li>实战</li> <li>职业路线</li> <li class="class-search"><img src="../../assets/search.png"></li> <li class="class-history"><img src="../../assets/history.png"></li> </ul> </div> </template> // scoped表示样式只在该组件中生效,不会影响其他页面 <style scoped> .c-header{ position:fixed; width:375px; top:0; background:#fff; box-shadow:0 2px 4px 0 rgba(0,0,0,.1); } .header-ul{ font-size:0; } .header-ul li{ display: inline-block; padding-left:20px; font-size:16px; color:#71777d; height:44px; line-height:44px; } .header-ul img{ width:18px; } .header-ul .class-search{ padding-left:60px; } </style>
创建列表组件
list文件夹下的index.vue
<template> <ul class="c-course"> <router-link to="/detail"> <li v-for="item in courseList"> <img :src="item.imgUrl"> <h1>{{item.title}}</h1> <p>{{item.msg}}</p> </li> </router-link> </ul> </template> <script> export default { props:{//过滤器 courseList:Array } } </script> <style scoped> .c-course{ padding:24px 0; background:#fff; } .c-course li{ position: relative; width:335px; height:72px; margin:0 auto 24px; } .c-course li img{ position:absolute; width:108px; border-radius:5px; } .c-course li h1{ font-size:15px; padding-left:124px; } .c-course li p{ font-size:14px; padding-left:124px; } </style>
底部组件
创建footer目录下的index.vue
<template> <div class="footer"> <ul class="footer-ul"> <li> <img src="../../assets/home.png" alt=""> <span>首页</span> </li> <li> <img src="../../assets/sea.png" alt=""> <span>发现</span> </li> <li> <img src="../../assets/download.png" alt=""> <span>下载</span> </li> <li> <img src="../../assets/me.png" alt=""> <span>我的</span> </li> </ul> </div> </template> <style scoped> .footer{ position:fixed; z-index:3; width:375px; background:#fff; border-top:1px solid #f3f5f7; bottom:0; } .footer-ul{ display:flex; } .footer-ul li{ display:flex; height:50px; flex:1; flex-direction: column; justify-content: center; align-items: center; font-size:10px; } .footer-ul li img{ width:24px; } </style>
首页文件home.vue
<template> <div class="home"> <v-header></v-header> <ul class="nav"> <li v-for="item in webList"> <img :src="item.imgUrl"><!-- 冒号用来接收变量 --> <span>{{item.name}}</span> </li> </ul> <v-list :courseList="courses"></v-list> <v-footer></v-footer> </div> </template> <script> //导入组件 import Header from '@/components/header/' import List from '@/components/list/' import Footer from '@/components/footer/' // 图片必须通过import来导入 import webImg from '@/assets/web.png' import webserviceImg from '@/assets/webservice.png' import moveImg from '@/assets/move.png' import dataImg from '@/assets/data.png' import bigdataImg from '@/assets/bigdata.png' import course1 from '@/assets/course1.jpg' import course2 from '@/assets/course2.jpg' import course3 from '@/assets/course3.jpg' import course4 from '@/assets/course4.jpg' import course5 from '@/assets/course5.jpg' export default { data(){ return{ webList:[], courses:[] } }, mounted(){ //值的初始化 this.webList=[{ imgUrl:webImg, name:"前端开发" }, { imgUrl:webserviceImg, name:"后端开发" }, { imgUrl:moveImg, name:"移动开发" }, { imgUrl:dataImg, name:"数据库" }, { imgUrl:bigdataImg, name:"云计算" }]; this.courses=[{ imgUrl:course1, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' }, { imgUrl:course2, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' }, { imgUrl:course3, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' }, { imgUrl:course4, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' }, { imgUrl:course5, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' },{ imgUrl:course1, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' }, { imgUrl:course2, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' }, { imgUrl:course3, title:'实例秒解sed和ak的秘密', msg:'中级,330人在学' }] }, components:{//注册组件 'v-header':Header, 'v-list':List, 'v-footer':Footer } } </script> <style scoped> .home .nav{ height:100px; padding-top:44px; background:#f3f5f7; overflow-x:scroll; white-space: nowrap; font-size:0; } .nav li{ width:88px; display:inline-block; text-align: center; font-size:14px; } .nav li img{ display:block; width:32px; margin:20px auto 12px; } </style>
详情页文件 detail.vue
<template> <div class="detail"> <div class="video"> <video src="http://v3.mukewang.com/shizhan/59f8498ae420e5be578b459b/H.mp4" controls="controls"></video> <router-link to="/"> <div class="video-back"><</div> </router-link> </div> <ul class="nav"> <li v-for="item in navArr">{{item}}</li> </ul> <div class="title"> <h1>{{title}}</h1> <p>{{des}}</p> </div> <ul class="question"> <li v-for="(item,index) in questionArr"> <h1>{{arrTitle[index]}}</h1> <p v-html="item"></p><!-- 由于读取的数据中存在html结构<br>,因此必须使用v-html --> </li> </ul> </div> </template> <style scoped> .detail{ position: relative; height:3.82rem; } .video video{ width:100%; height:100%; } .video-back{ position:absolute; top:21px; left:16px; text-align: center; color:#fff; font-size:18px; line-height:32px; border-radius: 3px; width:32px; height:32px; background:rgba(0,0,0,.5); } .nav{ position: relative; z-index:1; display:flex; box-shadow:0 2px 4px 0 rgba(0,0,0,0.1); } .nav li{ flex:1; text-align:center; line-height:44px; height:44px; background:#fff; font-size:14px; } .title{ padding: 24px 0 0 20px; margin-bottom: 8px; } .title h1{ font-size: 16px; color: #2B333B ; } .title p{ font-size: 14px; color: #71777D; padding : 16px 0 34px; width: 335px; } .question{ padding: 20px; background: #fff; } .question li h1{ font-size: 14px; color: #2B333B; } .question li p{ padding:12px 0 0 30px; font-size: 14px; color: #71777D ; } .question li:nth-child(1){ padding-bottom: 24px; } </style> <script> export default { data(){ return{ navArr:[], title:"", des:"", questionArr:[], arrTitle:["课程须知","老师告诉你能学到什么?"] } }, mounted(){ //真实开发中,这些数据需要通过后台读取 this.navArr=["章节","详情","评论","问答","记"]; this.title = "iOS基础教程之-Camera摄像头"; this.des = "从实例出发介绍我们的Camera,可以实现Camera属性检测,照片拍摄,视频录制,图片展示,录制视频"; this.questionArr=[ "本课程适合客户端产品经理,研发人员以及对iOS新特性感兴趣的人群", ` (1)数码相机相关的所有API<br/> (2)利用Camera实现相机的各种属性检测<br/> (3)利用Camera拍照、保存、遍历相册等功能<br/> (4)利用Camera拍摄视频、视频剪切功能 ` ] } } </script>