1、创建项目
vue create 项目名
创建后自动生成node-modules,后期如果与需要的不一致,可以重新安装
2、目录结构
- src
- assets(资源)
- css
- images
- components(组件)
- common(公共组件,可以抽离到别的项目的组件)
- content(当前业务相关的公共组件)
- views(视图)
- network(网络相关的文件夹)
- router(路由vue-router)
- store(vuex)
- common(公共js文件)
- assets(资源)
3、css初始化
- normalize.css GitHub上有代码
- base.css 自己的基础样式,css常用变量设置,引用normailize.css
- 在app.vue中引用base.css
<style>
@import 'assets/css/base.css';
</style>
4、配置别名
在根目录下添加vue.config.js文件,相关配置可以查看vue-cli4中的配置介绍,不满足可以上webpack上查找
- 设置别名(alias)
const path = require('path');
function resolve (dir) {
return path.join(__dirname, dir)
}
// 项目的主要配置文件
module.exports = {
// webpack 配置进行更细粒度的修改 https://cli.vuejs.org/zh/config/#chainwebpack
chainWebpack: (config)=>{
//修改文件引入自定义路径
config.resolve.alias
.set('@',resolve('./src'))
.set('components',resolve('./src/components'))
.set('views',resolve('./src/views'))
.set('assets',resolve('./src/assets'))
}
}
5、编辑规则设置
.editorconfig文件,cli4中没有,可以从别的项目中拷贝过来
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
6、使用vue-router
- 安装
npm install vue-router
- 创建router文件夹,添加index.js文件
import Vue from 'vue'
import Router from 'vue-router'
const Home = () => import('@/views/home/Home')
const Category = () => import('@/views/category/Category')
const Cart = () => import('@/views/cart/Cart')
const Me = () => import('@/views/me/Me')
Vue.use(Router)
const routes = [
{
path: '',
redirect: '/home'
},
{
path: '/home',
// 指定的组件
component: Home
},
{
path: '/category',
component: Category
},
{
path: '/cart',
component: Cart
},
{
path: '/me',
component: Me
},
]
const router = new Router({
routes,
mode:'history'//URL中去掉#
})
export default router
- main.js中引用router
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
7、使用axios
- 安装axios
npm install axios
- 创建network文件夹,添加request.js文件,内容如下
import axios from 'axios'
export function request(config) {
const instance = new axios.create({
baseURL:'http://ip',
timeout:5000
});
// 请求拦截器
instance.interceptors.request.use(config => {
//拦截后需要将拦截下来的请求数据返回发送
// console.log(config);
return config;
}, err => {
// console.log(err)
})
// 响应拦截器
instance.interceptors.response.use(res => {
// 拦截后需要将拦截下来处理成的结果返回
return res.data
}, err => {
console.log(err)
})
return instance(config)
}
- 创建模块网络请求文件,如home模块,home.js
import {request} from './request'
export function getHomeMultiData() {
return request({
url:'/home/multidata'
});
}
// 获取分类商品
export function getHomeGoods(type,page){
return request({
url:'/home/data',
params:{
type,
page
}
})
}
8、轮播
- swiper.vue
<template>
<div id="hy-swiper">
<div
class="swiper"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<slot></slot>
</div>
<slot name="indicator"> </slot>
<div class="indicator">
<slot name="indicator" v-if="showIndicator && slideCount > 1">
<div
v-for="(item, index) in slideCount"
class="indi-item"
:class="{ active: index === currentIndex - 1 }"
:key="index"
></div>
</slot>
</div>
</div>
</template>
<script>
export default {
name: "Swiper",
props: {
interval: {
type: Number,
default: 3000,
},
animDuration: {
type: Number,
default: 300,
},
moveRatio: {
type: Number,
default: 0.25,
},
showIndicator: {
type: Boolean,
default: true,
},
},
data: function () {
return {
slideCount: 0, // 元素个数
totalWidth: 0, // swiper的宽度
swiperStyle: {}, // swiper样式
currentIndex: 1, // 当前的index
scrolling: false, // 是否正在滚动
};
},
mounted: function () {
// 1.操作DOM, 在前后添加Slide
setTimeout(() => {
this.handleDom();
// 2.开启定时器
this.startTimer();
}, 100);
},
methods: {
/**
* 定时器操作
*/
startTimer: function () {
this.playTimer = window.setInterval(() => {
this.currentIndex++;
this.scrollContent(-this.currentIndex * this.totalWidth);
}, this.interval);
},
stopTimer: function () {
window.clearInterval(this.playTimer);
},
/**
* 滚动到正确的位置
*/
scrollContent: function (currentPosition) {
// 0.设置正在滚动
this.scrolling = true;
// 1.开始滚动动画
this.swiperStyle.transition = "transform " + this.animDuration + "ms";
this.setTransform(currentPosition);
// 2.判断滚动到的位置
this.checkPosition();
// 4.滚动完成
this.scrolling = false;
},
/**
* 校验正确的位置
*/
checkPosition: function () {
window.setTimeout(() => {
// 1.校验正确的位置
this.swiperStyle.transition = "0ms";
if (this.currentIndex >= this.slideCount + 1) {
this.currentIndex = 1;
this.setTransform(-this.currentIndex * this.totalWidth);
} else if (this.currentIndex <= 0) {
this.currentIndex = this.slideCount;
this.setTransform(-this.currentIndex * this.totalWidth);
}
// 2.结束移动后的回调
this.$emit("transitionEnd", this.currentIndex - 1);
}, this.animDuration);
},
/**
* 设置滚动的位置
*/
setTransform: function (position) {
this.swiperStyle.transform = `translate3d(${position}px, 0, 0)`;
this.swiperStyle[
"-webkit-transform"
] = `translate3d(${position}px), 0, 0`;
this.swiperStyle["-ms-transform"] = `translate3d(${position}px), 0, 0`;
},
/**
* 操作DOM, 在DOM前后添加Slide
*/
handleDom: function () {
// 1.获取要操作的元素
let swiperEl = document.querySelector(".swiper");
let slidesEls = swiperEl.getElementsByClassName("slide");
// 2.保存个数
this.slideCount = slidesEls.length;
// 3.如果大于1个, 那么在前后分别添加一个slide
if (this.slideCount > 1) {
let cloneFirst = slidesEls[0].cloneNode(true);
let cloneLast = slidesEls[this.slideCount - 1].cloneNode(true);
swiperEl.insertBefore(cloneLast, slidesEls[0]);
swiperEl.appendChild(cloneFirst);
this.totalWidth = swiperEl.offsetWidth;
this.swiperStyle = swiperEl.style;
}
// 4.让swiper元素, 显示第一个(目前是显示前面添加的最后一个元素)
this.setTransform(-this.totalWidth);
},
/**
* 拖动事件的处理
*/
touchStart: function (e) {
// 1.如果正在滚动, 不可以拖动
if (this.scrolling) return;
// 2.停止定时器
this.stopTimer();
// 3.保存开始滚动的位置
this.startX = e.touches[0].pageX;
},
touchMove: function (e) {
// 1.计算出用户拖动的距离
this.currentX = e.touches[0].pageX;
this.distance = this.currentX - this.startX;
let currentPosition = -this.currentIndex * this.totalWidth;
let moveDistance = this.distance + currentPosition;
// 2.设置当前的位置
this.setTransform(moveDistance);
},
touchEnd: function () {
// 1.获取移动的距离
let currentMove = Math.abs(this.distance);
// 2.判断最终的距离
if (this.distance === 0) {
return;
} else if (
this.distance > 0 &&
currentMove > this.totalWidth * this.moveRatio
) {
// 右边移动超过0.5
this.currentIndex--;
} else if (
this.distance < 0 &&
currentMove > this.totalWidth * this.moveRatio
) {
// 向左移动超过0.5
this.currentIndex++;
}
// 3.移动到正确的位置
this.scrollContent(-this.currentIndex * this.totalWidth);
// 4.移动完成后重新开启定时器
this.startTimer();
},
/**
* 控制上一个, 下一个
*/
previous: function () {
this.changeItem(-1);
},
next: function () {
this.changeItem(1);
},
changeItem: function (num) {
// 1.移除定时器
this.stopTimer();
// 2.修改index和位置
this.currentIndex += num;
this.scrollContent(-this.currentIndex * this.totalWidth);
// 3.添加定时器
this.startTimer();
},
},
};
</script>
<style scoped>
#hy-swiper {
overflow: hidden;
position: relative;
}
.swiper {
display: flex;
}
.indicator {
display: flex;
justify-content: center;
position: absolute;
width: 100%;
bottom: 8px;
}
.indi-item {
box-sizing: border-box;
width: 8px;
height: 8px;
border-radius: 4px;
background-color: #fff;
line-height: 8px;
text-align: center;
font-size: 12px;
margin: 0 5px;
}
.indi-item.active {
background-color: rgba(212, 62, 46, 1);
}
</style>
- SwiperItem.vue
<template>
<div class="slide">
<slot></slot>
</div>
</template>
<script>
export default {
name: "Slide"
}
</script>
<style scoped>
.slide {
width: 100%;
flex-shrink: 0;
}
.slide img {
width: 100%;
}
</style>
- index.js(方便引用,把swiper和swiperitem放一起,以后可以一起调用)
import Swiper from './Swiper'
import SwiperItem from './SwiperItem'
export {
Swiper, SwiperItem
}
- 使用轮播图
<swiper>
<swiper-item v-for="item of banner" :key="item.acm">
<a :href="item.link"><img :src="item.image" alt=""></a>
</swiper-item>
</swiper>