目录
一、项目的创建
Vue2
1.全局安装脚手架
npm install -g @vue/cli
2.搭建项目
vue create 项目名称
运行后,将得到图
通过手动选择Vue2和Vue3选项,分别创建Vue2或Vue3项目
3.运行项目
npm run serve
Vue3
pnpm create vite projectname # 创建项目
pnpm install # 安装依赖
pnpm run dev # 运行项目
二、搭建vue-router
1.Vue 2版本的创建语法:
(1)安装router
npm install vue-router@3.4.7
(2)在src下创建文件夹components(放置一般组件)和pages (放置路由组件)
在pages下创建HomePage.vue文件
<template>
<div>欢迎来到Home页面</div>
</template>
<style>
</style>
<script>
</script>
(3)在src下创建目录router,并在其下方创建index.js文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "@/pages/HomePage.vue";
import Essay from "@/pages/EssayPage.vue"
import TimeInfo from '@/components/TimeInfo.vue'
import EssInfo from "@/components/EssayInfo.vue"
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/essay',
name: 'Essay',
component: Essay,
children: [
{
path: '/essInfo',
name: 'EssInfo',
component: EssInfo,
},
{
path: '/timeInfo',
name: 'TimeInfo',
component: TimeInfo,
}
]
}
]
const router = new VueRouter({
mode: 'history', // mode设置路由模式,不配置这个参数时默认为hash模式。
routes,
linkActiveClass: 'active',
});
let originPush = VueRouter.prototype.push; //备份原push方法
VueRouter.prototype.push = function (location, resolve, reject) {
if (resolve && reject) { //如果传了回调函数,直接使用
originPush.call(this, location, resolve, reject);
} else { //如果没有传回调函数,手动添加
originPush.call(this, location, () => { }, () => { });
}
}
export default router
注意:在页面中用<router-view></router-view>时,在script中的用法为this.$router.push('essInfo'),路径处没有斜杠‘/’。
(4)在文件mian.js中引入我们所写的index.js文件
import Vue from 'vue'
import App from './App.vue'
import router from "./router/index.js"
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
2.Vue 3版本的创建语法:
(1)
·安装vue-router:pnpm i vue-router -D
·安装element-plus:pnpm i element-plus -D
完整引入的方法就看官网介绍
自动引入pnpm i -D unplugin-vue-components unplugin-auto-import
·安装pinia:pnpm i axios -D
在src下创建目录router,并在其下方创建index.ts文件
import {createRouter,createWebHashHistory,createWebHistory,RouteRecordRaw} from 'vue-router';
const routes:RouteRecordRaw[] = [
{
path:'/',
name:'Home', //在src下有component文件夹
component:()=>import('../components/Home.vue'), //或者() => import('@/views/HomeView.vue')
alias:'/index',
children: [
{
path: '/singer',
name: 'singer',
component: ()=>import('../components/one.vue')
},
{
path: '/all',
name: 'all',
component: ()=>import('../components/two.vue')
}
]
}
];
const router = createRouter({
history:createWebHashHistory(),
routes:routes
});
//全局前置路由
// from为从哪个页面来,to为去到哪个页面,next表示是否往下执行
// next():不跳转、next(true):允许跳转、next('login'):跳转到路径name为login的页面
router.beforeEach((to, from, next) =>{
//写判断语句等等
})
export default router;
(2)在文件mian.js引入我们所写的index.js文件
import { createApp } from "vue"
import './style.css'
import App from './App.vue'
import router from './router/index'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
//pinia:状态管理工具
import {createPinia} from 'pinia'
//Axios:对Axios请求的封装
import Axios from './request/request';
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.use(router)
app.use(Axios)
app.mount('#app')
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
(3)在配置文件vite.config.js进行配置
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
// ...
plugins: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})
(4) 编写axios配置文件
在src下创建文件夹request,在文件夹request下创建文件request.ts
/**axios封装
* 请求拦截、相应拦截、错误统一处理
*/
import axios from 'axios';
import router from '../router/index'
// let protocol = window.location.protocol; //协议
// axios.defaults.baseURL = protocol + "//" + host;
// let host = window.location.host; //主机
axios.defaults.baseURL = 'http://localhost:2001/vue_stu';
axios.defaults.headers.post['Content-Type']='application/json'
axios.interceptors.request.use( //响应拦截
async config => {
// 每次发送请求之前判断vuex中是否存在token
// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
config.headers.token = sessionStorage.getItem('token')
return config;
},
error => {
return Promise.reject(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:
break
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
sessionStorage.clear()
router.push('/login')
break
// 404请求不存在
case 404:
break;
// 其他错误,直接抛出错误提示
default:
}
return Promise.reject(error.response);
}
}
);
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
const $get = (url:any, params:any) => {
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 [请求时携带的参数]
*/
const $post = (url:any, params:any) => {
return new Promise((resolve, reject) => {
axios.post(url, JSON.stringify(params)) //JSON.stringify()方法用于将 JavaScript 值转换为 JSON 字符串
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
/**
* put方法,对应put请求
* @param {String} url
* @param {Object} params
* @returns {Promise}
*/
const $put = (url:any, params:any, type = 'application/json')=> {
return new Promise((resolve, reject) => {
axios.put(url, params)
.then(response => {
resolve(response.data)
}, err => {
reject(err)
})
})
}
/**
* del方法,对应delet请求
* @param {String} url
* @param {Object} params
* @returns {Promise}
*/
const $del = (url:any, params:any, type = 'application/json')=> {
return new Promise((resolve, reject) => {
console.log(params)
axios.delete(url, {
params: params,
headers: {
'Content-Type': type
}
})
.then(response => {
resolve(response.data)
})
.catch(err => {
reject(err)
})
})
}
//下面是vue3必须加的,vue2不需要,只需要暴露出去get,post方法就可以
export default {
install: (app:any) => {
app.config.globalProperties['$get'] = $get;
app.config.globalProperties['$post'] = $post;
app.config.globalProperties['$put'] = $put;
app.config.globalProperties['$del'] = $del;
app.config.globalProperties['$axios'] = axios;
}
}
在src下创建文件shime-vue.d.ts
declare module 'qs'
3.在APP.vue中配置写出组件的出口
<template>
<div id="app">
<!-- Router-view:路由的出口 -->
<router-view></router-view>
</div>
</template>
<style>
</style>
<script>
export default {
name: 'App',
}
</script>
三、使用vuex作为状态存储仓库
1.安装vuex
npm install vuex --save
这时如果直接安装vuex,不指定版本的话,就会直接安装最新的vuex的版本。所以会出现报错。
vuex分3.x版本和4.x版本,分别对应vue2.0与3.0,因此上面的是安装vue3.0版本的。
vue2.0需要带上版本号
npm install --save vuex@3
2.创建store
1、Vuex的状态存储是响应式的:若store中的状态发生变化,那么相应的组件也会被更新
2、不能直接改变store中的状态:改变store中的状态的唯一途径是提交(commit)mutation
(1)创建实例
在 src下创建store的文件夹,并在这个文件夹下创建index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
//Vue.useAttrs(Vuex)
Vue.use(Vuex)
//创建仓库
const store = new Vuex.Store({
state: {
name: "Meier",
age: 18,
imgURL: "http://xxxxxx",
friends: [
{ id: 1, name: "a", age: 20 },
{ id: 2, name: "b", age: 30 },
{ id: 3, name: "c", age: 40 }
]
},
getters: {},
mutations: {},
actions: {},
modules: {}
})
export default store
踩坑注意: 创建store对象时“const store = new Vuex.Store”,如果遇到“报错:vuex__WEBPACK_IMPORTED_MODULE_1__.default.store is not a constructor”,则是因为“Vuex.Store”的S不能小写
(2)挂载
将仓库挂载到vm对象。在main.js文件中:
import Vue from 'vue'
import App from './App.vue'
import router from "./router/index.js"
import store from "./store/index.js"
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
store,
}).$mount('#app')
(3)配置函数及用法
- getters:类似于计算属性,作用是对外输出
getters:{
// 输出属性给组件
total(state){
return state.age;
},
}
- mutations:如果要修改state中数据,必须通过mutations进行修改(同步的),专门负责直接修改state中的数据,不能进行异步操作
mutations: {
//默认第一个参数传state
changeAge(state,age){
//变更状态
state.age = age
}
},
在组件中使用:
$store.commit('事件名称',参数)
//this.$store.commit('changeAge',100)
- actions:异步处理修改state中的数据
组件调用当前actions中的 方法,actions方法调用mutations的方法,修改state数据。
actions: {
// 默认第一个参数传一个跟store一样的对象
increment(context,name){
//假设fnAsync是一个异步业务函数
fnAsync(()=>{
context.commit('changeName',name);
},2000)
}
}
在组件中使用:
this.$store.dispatch('事件名称',参数)
//this.$store.dispatch('increment','aaa')
- modules:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter
//分块设计:
const moduleA = {
namespaced: true,//局部命名空间(让state的中变量与其他模块中的同名变量不冲突)
state: { msg:1 },
mutations: { change(state,n){state.msg=n} },
actions: { change(context,n){context.commit("change",n)} },
getters: { x(state){return state.msg} }
}
const moduleB = {
namespaced: true,//局部命名空间
state: { msg:1 },
mutations: { change(state,n){state.msg=n} },
actions: { change(context,n){context.commit("change",n)} },
getters: { x(state){return state.msg} }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
在组件中使用:
this.$store.state.a.msg // -> moduleA 的状态
this.$store.state.b.msg // -> moduleB 的状态
this.$store.commit("a/change",100)-> moduleA 的mutations
this.$store.commit("b/change",200)-> moduleB 的mutations
this.$store.getters["a/x"]-> moduleA 的getters
this.$store.getters["b/x"]-> moduleB 的getters
this.$store.dispatch("a/change",100)-> moduleA 的actions
this.$store.dispatch("b/change",200)-> moduleB 的actions
3.组件中使用vuex
(1)在模板中使用
可以直接拿,但这样比较繁琐,所以还是在computed里面封装一下再使用比较好
<template>
<div v-show="$store.state.showSearch">
<div>Home当前昵称:{{ $store.state.name }}</div>
<div>Computed当前昵称:{{ storeName }}</div>
<div>Setup当前昵称:{{ name }}</div>
</div>
</template>
(2)setup中使用
必须要加toRefs才是响应式,数据的改变还是要commit到store中去改变
<script setup>
import {toRefs} from 'vue'
import { useStore } from 'vuex'
const store = useStore()
const { name } = toRefs(store.state)
</script>
·数据的改变
//因为已经在main.js全局引入了,所以在页面中不需要import vuex
//数据的同步改变 需要在mutations中定义一个mutation函数
state: {
showSearch: false,
},
mutations: {
changeShowSearch(state, showSearch) {
state.showSearch = showSearch;
}
},
//在页面中,需要通过调用commit来执行mutation函数
this.$store.commit('changeShowSearch',false);
(3)options api中使用
<script>
export default{
computed:{
storeName(){
return this.$store.state.name
}
}
}
</script>
4.vuex与pinia的比较
- pinia 没有mutation,只有state,getters,action【同步、异步】使用 action 来修改state数据。
- pinia 语法上比 vuex 更容易理解和使用,有完整的 TypeScript 支持,比 vux 更容易添加
- pinia 没有 modules 配置,每一个独立的仓库都是 definStore 生成出来的。
- pinia state 是一个对象返回一个对象和组件的data是一样的语法。
- pinia store 的 action 被调度为常规的函数调用,vuex 是使用 dispatch 方法或 MapAction 辅助函数
- vuex 支持调试功能,如时间旅行和编辑。pinia 不支持。
四、使用element作为组件库
1、引入组件
npm i element-ui -S
(1)完整引入(在 main.js 中写入以下内容)
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
(2)按需引入 (借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的)
npm install babel-plugin-component -D
- 将 .babelrc 修改为
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
- 如果只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容 :
import Vue from 'vue';
import { Button, Select } from 'element-ui';
import App from './App.vue';
Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
/* 或写为
* Vue.use(Button)
* Vue.use(Select)
*/
new Vue({
el: '#app',
render: h => h(App)
});
2、使工程组件化
因此不会再app.vue里面直接开发,而是新开一个页面组件。注意:.vue文件采用的驼峰命名法,否则语法检查会报错。
直接到官网处,看中什么就复制什么过来直接用。
然后在需要用到的.vue文件当中引入该页面组件,在组件当中增加以下三个地方即可。
五、router-link和router-view
router-link设置路由跳转,router-view根据路由显示组件
1、router-link
<router-link to="/url">
<li>
<a>goto</a>
</li>
</router-link>
2、router-view
首先在router/index.js上设置路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "@/pages/HomePage.vue";
import Essay from "@/pages/EssayPage.vue"
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
}, {
path: '/essay',
name: 'Essay',
component: Essay
}
]
const router = new VueRouter({
mode: 'history', // mode设置路由模式,不配置这个参数时默认为hash模式。
routes,
linkActiveClass: 'active',
})
export default router
在router-view上显示(就是根据路由显示B组件还是C组件)
<router-view>
</router-view>
六、vue2引入图片
<template>
<div class="demo-type" :style="backgroundDiv">
<div>
<el-avatar :src="headDiv" :size="100"/>
</div>
</div>
</template>
<script >
export default{
data(){
return {
// 1、绑定在标签样式中
backgroundDiv: {
backgroundImage: 'url(' + require('@/assets/image/mainPic.png') + ')'
},
// 2、在element-ui中自带的路径属性
headDiv: require('@/assets/image/head.png')
};
},
methods:{}
}
</script>
持续更新中...