1. 使用vue/cli创建项目(安装vue/cli)
vue create my-project
创建过程步骤如下:
Manuually select features
选择 Babel(es6语法编译器) Router(路由模块) Vuex(全局状态管理) Linter / Formatter(语法格式规范校验 ESLint + Standard) Css Pre-processors(css/sass/less处理器)等个人定制
2. 项目创建完成 引入Vant
npm i vant -S
在main.js中引用Vant
// 引入vant
import Vant from 'vant'
import 'vant/lib/index.css'
Vue.use(Vant)
3. 配置浏览器适配 rem布局 此功能会将px 转成rem 适配手机端
npm i amfe-flexible
npm i postcss-pxtorem
项目根目录新建.postcssrc.js文件:配置如下:
module.exports = {
plugins: {
// autoprefixer: {
// browsers: ['Android >= 4.0', 'iOS >= 8'],
// },
'postcss-pxtorem': {
// lib flexible的 REM 解决方案 把一行分成10份 每份1/10
// rootValue 应该设计稿的 1/10
// 我们的设计稿 750 所以为 75
// 但是Vant建议设置 37.5 应为Vant基于37.5 所以使用设置37.5后实际尺寸都要 /2
// 有没有更好的办法?
// 如果是Vant的样式就按照 37.5 转换 如果是自己的就用 75
// 查询文档发现 rootValue 支持两种类型 一种数字 一种函数
// 函数: 可以动态处理返回值 postcss-pxtorem 处理每个 css 文件都会来调用这个函数
// rootValue: 37.5,
rootValue({ file }){
return file.indexOf('vant') !== -1 ? 37.5 : 75
},
// 配置要转换的css属性
propList: ['*'],
},
},
};
4. 项目其他文件配置如下:
api/user.js
import post from '@/utils/request'
export const login = (data) => {
return post({
url: '/app/v1_0/authorizations',
data
})
}
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/login',
name: 'login',
component: () => import('@/views/login')
}
]
const router = new VueRouter({
routes
})
export default router
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
utils/request.js
// import axios from 'axios'
// const request = axios.create({
// baseURL: 'http://ttapi.research.itcast.cn/' // 接口基准地址
// })
// export default request
/** axios封装
* 请求拦截、相应拦截、错误统一处理
*/
import axios from 'axios'
import QS from 'qs'
// 环境的切换
if (process.env.NODE_ENV === 'development') {
axios.defaults.baseURL = 'http://ttapi.research.itcast.cn/'
} else if (process.env.NODE_ENV === 'debug') {
axios.defaults.baseURL = 'http://ttapi.research.itcast.cn/'
} else if (process.env.NODE_ENV === 'production') {
axios.defaults.baseURL = 'http://ttapi.research.itcast.cn/'
}
// 请求超时时间
axios.defaults.timeout = 10000
// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
// 请求拦截器
axios.interceptors.request.use(
config => {
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
const token = localStorage.getItem('token')
token && (config.headers.Authorization = token)
return config
},
error => {
return Promise.error(error)
})
// 响应拦截器
axios.interceptors.response.use(
response => {
if (response.status === 200) {
return Promise.resolve(response)
} else {
return Promise.reject(response)
}
},
// 服务器状态码不是200的情况
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
console.log('未登录')
break
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
console.log('登录过期')
// 清除token
localStorage.removeItem('token')
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
break
// 404请求不存在
case 404:
console.log('网络请求不存在')
break
// 其他错误,直接抛出错误提示
default:
console.log(error.response.data.message)
}
return Promise.reject(error.response)
}
}
)
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function get (url, params) {
return new Promise((resolve, reject) => {
axios.get(url, {
params: params
})
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err.data)
})
})
}
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post (url, params) {
return new Promise((resolve, reject) => {
axios.post(url, QS.stringify(params))
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err.data)
})
})
}
export function request (url, params, method) {
}
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 全局样式文件
import './styles/index.less'
// 引入vant
import Vant from 'vant'
import 'vant/lib/index.css'
// 动态设置 REM 基准值 npm i amfe-flexible
import 'amfe-flexible'
Vue.use(Vant)
Vue.config.productionTip = true
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
.postcssrc.js
module.exports = {
plugins: {
// autoprefixer: {
// browsers: ['Android >= 4.0', 'iOS >= 8'],
// },
'postcss-pxtorem': {
// lib flexible的 REM 解决方案 把一行分成10份 每份1/10
// rootValue 应该设计稿的 1/10
// 我们的设计稿 750 所以为 75
// 但是Vant建议设置 37.5 应为Vant基于37.5 所以使用设置37.5后实际尺寸都要 /2
// 有没有更好的办法?
// 如果是Vant的样式就按照 37.5 转换 如果是自己的就用 75
// 查询文档发现 rootValue 支持两种类型 一种数字 一种函数
// 函数: 可以动态处理返回值 postcss-pxtorem 处理每个 css 文件都会来调用这个函数
// rootValue: 37.5,
rootValue({ file }){
return file.indexOf('vant') !== -1 ? 37.5 : 75
},
// 配置要转换的css属性
propList: ['*'],
},
},
};
babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
package.json
{
"name": "toutiao-m",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"amfe-flexible": "^2.2.1",
"axios": "^0.21.0",
"core-js": "^3.6.5",
"vant": "^2.10.11",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/eslint-config-standard": "^5.1.2",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^6.2.2",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"lint-staged": "^9.5.0",
"postcss-pxtorem": "^5.1.1",
"vue-template-compiler": "^2.6.11"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,vue}": [
"vue-cli-service lint",
"git add"
]
}
}