官方文档
这个项目我们尽量用yarn命令。
# 1、创建项目的命令
//npm
npm init @vitejs/app
//yarn
yarn create @vitejs/app
// 创建项目示例 npm init @vitejs/app [project-name]
yarn create @vitejs/app [project-name]
//下载node_modules
yarn
# 2、选择创建vue项目
# 3、选择你想要的版本
4、回车后项目下载完成
5、安装node_nodules
yarn
6、安装我们开发需要的依赖,执行一下命令
//下载依赖
//开发依赖
yarn add vue-router@next vuex@next element-plus axios -S
//生产依赖 yarn add sass -D
//删除依赖(只是展示一下命令,并不需要去操作)
yarn remove vue-router@next vuex@next element-plus axios
yarn remove sass
7、我们的package.json文件来判断安装是否成功
{
"name": "vuevite",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"axios": "^0.21.1",
"element-plus": "^1.0.2-beta.70",
"vue": "^3.0.5",
"vue-router": "^4.0.11",
"vuex": "^4.0.2" },
"devDependencies": { "@vitejs/plugin-vue": "^1.3.0",
"@vue/compiler-sfc": "^3.0.5",
"sass": "^1.37.5",
"vite": "^2.4.4"
}
}
8、注意事项
vite.config.js 用来配置项目的参数,类似vue.config.js
index.html
// type="module"让浏览器能识别ES6语法
<script type="module" src="/src/main.js"></script>
2、配置项目所需架构
1、目录结构
vite.config.js作用和vue.config.js作用相似,但是配置的方式会有所不同,请仔细查看api文档进行配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
const path = require('path')
// https://vitejs.dev/config/
export default defineConfig({
//修改服务的host和port
server:{
host:'127.0.0.1',
port:'8080'
},
//转换./src文件夹为@符号
resolve: {
alias:{
'@': path.resolve( __dirname, './src' )
}
},
plugins: [vue()]
})
vite获取环境变量的方式和在普通vue项目中不同
vue项目中获取环境变量process.env
import { createApp } from 'vue'
import App from './App.vue'
console.log("环境变量=>",import.meta.env);
createApp(App).mount('#app')
修改项目启动的模式package.json
"scripts": {
"dev": "vite --mode development",
"build": "vite build",
"serve": "vite preview"
},
修改的规则
.env # 所有情况下都会加载
.env.local # 所有情况下都会加载,但会被 git 忽略
.env.[mode] # 只在指定模式下加载
.env.[mode].local # 只在指定模式下加载,但会被 git 忽略
现在我在之前配置了--mode development
项目启动后就会默认加载.env.development
VITE_BASE_URL=/api
为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码。
可以通过import.meta.env.VITE_SOME_KEY获取到定义过的这个变量。
举例:
main.js
import { createApp } from 'vue'
import App from './App.vue'
console.log("环境变量=>",import.meta.env);
createApp(App).mount('#app')
2、如何使用scss文件初始化样式
暂时不用深究语法
可以自行删减
./css/global.css
@charset "utf-8";
// 变量存储
// 字体Unicode编码 微软雅黑:\5FAE\8F6F\96C5\9ED1 , 宋体:\5B8B\4F53
$pcFont: '\5FAE\8F6F\96C5\9ED1', '\5B8B\4F53', arial;
$defaultColor: #333;
$mobileFont: 'Helvetica Neue', Helvetica, STHeiTi, Microsoft YaHei, sans-serif, Microsoft JhengHei, Arial;
$browser: null;
%display {
display:inline-block;
*display:inline;
*zoom:1;
}
%text-indent {
font-size:0;
text-indent:-99999em;
overflow:hidden;
}
%box-sizing {
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
-o-box-sizing:border-box;
box-sizing:border-box;
}
// 绝对居中
@mixin center($width, $height) {
position: absolute;
left:50%;
top:50%;
width:$width;
height:$height;
margin:(-$height / 2) 0 0 (-$width / 2);
}
// 设置动画名称
@mixin animation($aniName) {
-webkit-animation:$aniName;
-moz-animation:$aniName;
-o-animation:$aniName;
animation:$aniName;
}
// 设置延迟执行时间
@mixin animation-delay($time) {
-webkit-animation-delay:$time;
-moz-animation-delay:$time;
-o-animation-delay:$time;
animation-delay:$time;
}
// 设置阴影
@mixin box-shadow($shadow...) {
-webkit-box-shadow:$shadow;
-moz-box-shadow:$shadow;
-o-box-shadow:$shadow;
box-shadow:$shadow;
}
// 圆角
@mixin border-radius($radius) {
-webkit-border-radius:$radius;
-moz-border-radius:$radius;
-o-border-radius:$radius;
border-radius:$radius;
}
// 设置过渡
@mixin transition($transition...) {
-webkit-transition:$transition;
-moz-transition:$transition;
-o-transition:$transition;
transition:$transition;
}
// 设置旋转位置
@mixin transform-origin($origin...) {
-webkit-transform-origin:$origin;
-moz-transform-origin:$origin;
-o-transform-origin:$origin;
transform-origin:$origin;
}
@mixin transform($transform...) {
-webkit-transform:$transform;
-moz-transform:$transform;
-o-transform:$transform;
transform:$transform;
}
// 设置关键帧
@mixin keyframes($name) {
@-webkit-keyframes #{$name} {
$browser: '-webkit-'; @content;
}
@-moz-keyframes #{$name} {
$browser: '-moz-'; @content;
}
@-o-keyframes #{$name} {
$browser: '-o-'; @content;
}
@keyframes #{$name} {
$browser: ''; @content;
}
}
/* ********************重置样式 reset******************** */
/* *********PC端********** */
body, dl, dd, h1, h2, h3, h4, h5, h6, p, form, figure, figcaption {
margin:0px;
}
ul, ol {
list-style:none;
margin:0px;
padding:0px;
}
body {
font:14px/1.5 $pcFont;
width:100%;
color: $defaultColor;
overflow-x:hidden;
}
h1,h2,h3,h4,h5,h6 {
font-weight:normal;
}
/* 清除点击出现虚拟框 */
a{
outline:none;
text-decoration:none;
-webkit-tap-highlight-color:rgba(0,0,0,0);
&:focus{
outline:0;
}
&:link,
&:visited {
color: $defaultColor;
text-decoration:none;
}
}
a img {
border:none;
}
input, textarea, select {
outline:none;
font:12px/1.5 $pcFont;
}
/* 清除浮动 */
.clearfix {
*zoom:1;
&:after {
display:block;
content:"\200B";
clear:both;
height:0;
}
}
/* *********移动端********** */
body, dl, dd, h1, h2, h3, h4, h5, h6, p, form, figure, figcaption {
margin:0px;
}
/* 改变盒子模型 */
section, article, nav, aside, footer, header, div, p, ul, li, input, textarea {
display: block;
@extend %box-sizing;
}
html, body {
-webkit-user-select: none;
/* 禁止选中文本 */
user-select: none;
-webkit-text-size-adjust: 100%;
/* iphone禁用文字大小调整 */
-ms-text-size-adjust: 100%;
}
html {
font-size:625%;
}
body{
font:.16rem/1.6 $mobileFont;
color:#333;
-webkit-overflow-scrolling: touch;
}
h1, h2, h3, h4, h5, h6{
font-weight:normal;
}
/* 清除点击虚拟框 */
a, div, p, span, ul, li, i, img, input {
outline:0;
text-decoration:none;
-webkit-tap-highlight-color:rgba(0,0,0,0);
}
a:focus{
outline:0;
}
a:link,a:visited{
color:$defaultColor;
text-decoration:none;
}
a img{
border:0 none;
}
a, img {
-webkit-touch-callout: none;
/* 禁止长按链接与图片弹出菜单 */
}
input, textarea, select {
outline: none;
color: $defaultColor;
font-family: $mobileFont;
}
input {
/* 清除 iphone 中 input 默认样式 */
-webkit-appearance: none;
}
/* 清除浮动 */
.clearfix {
*zoom:1;
&:after {
display:block;
content:"\200B";
clear:both;
height:0;
}
}
3、配置路由文件
vite的底层是rollup,所以没有这个chunk
import { createRouter, createWebHashHistory } from 'vue-router';
import Login from '../views/Login.vue';
const routes = [
{
path:'/',
name:'login',
component:Login
},
{
path:'/home',
name:'home',
component:()=>import('../views/Home.vue')
}
]
const router = createRouter({
history:createWebHashHistory(),
routes
})
export default router;
4、如何配置axios
./config/index.js
/**
* 统一的环境变量配置
*/
const env = import.meta.env.MODE || 'production';
const EnvConfig = {
//开发环境
development:{
baseApi:'/api',
mockApi:'https://www.fastmock.site/mock/eab0ffc31201e85b4aa3810df5e28237/api'
},
test:{
baseApi:'/',
mockApi:'/'
},
//线上环境
production:{
baseApi:'www.babdfjkdh.com/api' // 假的地址,举例用的
}
}
export default {
env,
mock:true,
namespace:'punch', // 用于sessionStroage的封装
...EnvConfig[env]
}
简单版./utils/request.js
import axios from 'axios'
import config from './../config'
// 创建axios实例对象,添加全局配置
const _axios = axios.create({
baseURL: config.baseApi,
timeout: 10000
})
// 添加请求拦截器
_axios.interceptors.request.use((config)=>{
// 在发送请求之前做些什么
return config;
},(error)=>{
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
_axios.interceptors.response.use((res)=> {
// 对响应数据做点什么
const { code, data } = res.data;
if (code === 200) {
return data;
}
return res;
},(error)=>{
// 对响应错误做点什么
return Promise.reject(error);
});
/**
* 请求核心函数,mock数据切换的逻辑
* @param {*} options 请求配置
*/
function request(options) {
//兼容。没有传HTTP方法的时候,默认使用get方法
options.method = options.method || 'get'
//因为axiosget传参要使用param(固定写法),所以需要转换一下
if (options.method.toLowerCase() === 'get') {
options.params = options.data;
}
//在调用接口的时候有没有传mock这个参数
let isMock = config.mock;
//线上环境必须使用后台接口的路径的一个安全措施
if (config.env === 'production') {
_axios.defaults.baseURL = config.baseApi
} else {
//如果不是线上"production"线上环境
//就判断我们传的mock是true还是false来做一个所有mock数据的开关
_axios.defaults.baseURL = isMock ? config.mockApi : config.baseApi
}
return _axios(options)
}
export default request;
./utils/request.js
import axios from 'axios'
import config from './../config'
import router from '../router'
import { ElMessage } from 'element-plus'
const TOKEN_INVALID = 'Token认证失败,请重新登录'
const NETWORK_ERROR = '网络请求异常,请稍后重试'
// 创建axios实例对象,添加全局配置
const service = axios.create({
baseURL: config.baseApi,
timeout: 10000
})
// 请求拦截
service.interceptors.request.use((req) => {
const headers = req.headers;
if (!headers.Authorization) headers.Authorization = 'Bearer ';
return req;
})
// 响应拦截
service.interceptors.response.use((res) => {
const { code, data, msg } = res.data;
if (code === 200) {
return data;
} else if (code === 401) {
ElMessage.error(TOKEN_INVALID)
setTimeout(() => {
router.push('/login')
}, 1500)
return Promise.reject(TOKEN_INVALID)
} else {
ElMessage.error(msg || NETWORK_ERROR)
return Promise.reject(msg || NETWORK_ERROR)
}
})
/**
* 请求核心函数
* @param {*} options 请求配置
*/
function request(options) {
//兼容。没有传HTTP方法的时候,默认使用get方法
options.method = options.method || 'get'
//因为axiosget传参要使用param(固定写法),所以需要转换一下
if (options.method.toLowerCase() === 'get') {
options.params = options.data;
}
//在调用接口的时候有没有传mock这个参数
let isMock = config.mock;
//线上环境必须使用后台接口的路径的一个安全措施
if (config.env === 'production') {
service.defaults.baseURL = config.baseApi
} else {
//如果不是线上"production"线上环境
//就判断我们传的mock是true还是false来做一个所有mock数据的开关
service.defaults.baseURL = isMock ? config.mockApi : config.baseApi
}
return service(options)
}
export default request;
./api/index.js
import request from '../utils/request.js';
export const login = (params) =>{
return request({
url: '/users/login',
method: 'post',
data:params
})
}
在页面上调用的时候可以引入这个login来使用
5、注册全局可用的方法
./main.js
举例如下,请直接看如下代码第12行
import { createApp } from 'vue'
import ElementPlus from 'element-plus';
import router from './router'
import 'element-plus/lib/theme-chalk/index.css';
import App from './App.vue'
import storage from './utils/storage';
const app = createApp(App)
//全局注册
app.config.globalProperties.$storage = storage
console.log("环境变量=>",import.meta.env);
app.use(ElementPlus).use(router).mount('#app')
./utils/storage
/**
* localstorage封装
* @author 谭威
*/
import config from '../config'
//config.namespace 为punch自定义
export default {
//设置一个值
setItem(key,val){
let storage = this.getStorage();
storage[key] = val;
window.localStorage.setItem(config.namespace,JSON.stringify(storage))
},
//获取一个值
getItem(key){
return this.getStorage()[key]
},
//从localStorag中取出数据
getStorage(){
return JSON.parse(window.localStorage.getItem(config.namespace) || '{}')
},
//清除一个值
cleanItem(key){
let storage = this.getStorage();
delete storage[key];
window.localStorage.setItem(config.namespace,JSON.stringify(storage))
},
//清除所有
cleanAll(){
window.localStorage.clear()
}
}
如何去页面调用呢?这里讲的是在setup中调用的方法
import { getCurrentInstance, onMounted } from 'vue'
const { proxy, ctx } = getCurrentInstance()
onMounted(()=>{
//注册
proxy.storage.setItem('age','18');
//清空所有
proxy.$storage.cleanAll();
})