Vue的基础使用及基于vue/cli的开发
安装vue/cli
安装:
npm i -g @vue/cli
查看版本号:
vue --version
卸载:
npm uninstall -g @vue/cli; // 4.x
npm uninstall -g vue-cli // 3.x
创建vue项目
vue create 项目名
目录介绍
public/ 静态资源目录,不需要编译的文件资源 ,都放里面。
src/ 项目开发源目录
babel.config.js E6 =>es5的配置文件;
.gitignore GIT管理配置文件,设置要忽略的目录。
src–assets/ 放需要webpack编译东西;
components 各类子组件的目录或直接放子组件文件;
router Vue中,前端路由配置文件
store VueX状态管理目录
views 存储页面级别的vue组件;
App.vue 项目的默认的根组件;
main.js 项目的入口配置文件;
Vue生命周期
生命周期钩子函数:是每个 Vue 实例在被创建时都要经过一系列的初始化过程,例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
VUE提供一个让用户运行代码的机会的一个API,而这些API,就是生命周期钩子函数。
beforeCreate: 就是Vue实例初始化时,完成创建实例之前;
created: Vue实例初始化结束,实例创建成功之后。
beforeMount: Vue模板编译成功后,在挂载到el指定的DOM之前;
mounted: 挂载到el指定的DOM成功之后。
beforeUpdate: 在更新数据时,完成页面渲染之前;
updated: 重新渲染页面成功之后;
beforeDestroy: 在切换组件或离开组件时,触发这个钩子函数,即销毁组件之前。
destroyed: 销毁组件之后
Vue-router
Vue-router:是通过地址栏的变化,来处理要切换的组件的渲染,并且可以指定渲染的窗口。仅仅是前端单页的一个地址管理,不是后台的接口;
<router-view>
<router-view>组件是一个 functional 组件,渲染路径匹配到的视图组件。<router-view> 渲染的组件还可以内嵌自己的 <router-view>,根据嵌套路径,渲染嵌套组件。
<router-view name="First">
<About />
</router-view>
<router-link>
<router-link>组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 <a>标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。
属性:
to: 表示目标地址
to="/home"
:to="{name:'', params:{id:1}}" this.$route.params.id
:to="{path:'', query:{id: 1}}" this.$route.query.id;
路由的使用
根路由、重定向、异步导入路由、子路由、默认路由、404页面
//router index.js
import Vue from 'vue' // 导入Vue
import VueRouter from 'vue-router' // 导入Vue路由模块
// import Home from '../views/Home.vue' //同步导入常用的组件;
Vue.use(VueRouter) //让Vue使用Vue-router模块;
const routes = [
// 每一个对象,就是配置的一条路由信息。
{
path: '/', //表示访问根路由,渲染首页
name: 'IndexPage', //路由名,在使用<router-link to="{name: 'Home'}">
// component: Home //使用哪一个组件来渲染,组件名称。通过import 导入的;
redirect: "/home" //重定向路径
},
// 数组的一级成员,对应是一级路由,一级路由的组件,就显示在最外面的<router-view>
{
path: "/about",
name: "about",
component: () => import("../components/about/About.vue"),//异步导入常用的组件;
// 一级下面的children:里面的路由,对应的就是二级路由;如果不添加子<router-view>,则不能显示二级路由对应的组件。对应的地址:/about/xxx
// 只要在childrend添加了子路由,就必须再嵌套一个<router-view>。
children: [
{
path: '',// 设置一个默认的二级路由的页面
component: () => import("../components/about/AboutQyjs.vue")
},
{
path: "qyjs",//子路由不要以“/”开头,
name: "qyjs",
component: () => import("../components/about/AboutQyjs.vue"),
// 二级路由里面的children, 对应的就是三级路由:/about/qyjs/xx
// 当前三级路由是在qyjs组件页中添加三级,所以 <router-view />就必须 要写在AboutQyjs.vue中。
children: [
{
path: "a",
name: "qyjsA",
component: () => import("../components/about/AboutQyjsA.vue")
},
{
path: "b",
name: "qyjsB",
component: () => import("../components/about/AboutQyjsB.vue")
}
]
},
{
path: "*",
name: "page404",
component: () => import("../components/404/Page404.vue")
}
]
// 实例化一个VueRouter路由对象,并把路由配置做参数对象;
const router = new VueRouter({
routes
})
// 公开 router路由配置模块。
export default router
动态路由
params 传参方式:name和params
1、声明式传参
- 直接传参(单参&多参): <router-link to="/getdata/data1/data"></router-link>
- 对象传参(单参&多参):<router-link :to=’{name:“GetData”,params:{key1:“data1”,key2:“data2”}}’></router-link>
2、编程式传参
- 直接传参(单参&多参):this.$router.push("/getdata/data1/data2")
- 对象传参(单参&多参):this.$router.push({name:“GetData”,params:{key1:“data1”,key2:“data2”}})
3、接收参数
- 模板页面中:$route.params.key 或 this.$route.params.key
- this实例中:this.$route.params.key
params路由设置 /:key
{
path:"/getdata/:key1/:key2",
name:"getData",
component:()=>import("@/views/getData.vue")
}
query 传参方式:name/path和query
1、声明式传参
- 直接传参(单参&多参): <router-link :to="/getdata?key1=data1&key2=data2"></router-link>
- name 对象传参(单参&多参): <router-link :to=’{name:“GetData”,query:{key1:“data1”,key2:“data2”}}’></router-link>
- path对象传参(单参&多参): <router-link:to=’{path:"/getdata",query:{key1:“data1”,key2:“data2”}}’></router-link>
2、编程式传参
- 直接传参(单参&多参): this.$router.push("/getdata?key1=data1&key2=data2")
- name 对象传参(单参&多参): this.$router.push({name:"",query:{key1:“data1”,key2:“data2”}})
- path对象传参(单参&多参): this.$router.push({path:"",query:{key1:“data1”,key2:“data2”}})
3、接收参数
- 模板页面中:$route.query.key 或 this.$route.query.key
- this实例中:this.$route.query.key
query路由设置
{
path:"/getdata",
name:"getData",
component:()=>import("@/views/getData.vue")
}
Element UI
安装
npm i element-ui -S
引入
main.js 导入element-ui模块
import ElementUI from ‘element-ui’
导入CSS
import ‘element-ui/lib/theme-chalk/index.css’;
Vue.use(模块对象)
Vue.use(ElementUI);
基础使用
布局
用于布局的容器组件,方便快速搭建页面的基本结构:
<el-container>外层容器。当子元素中包含 <el-header> 或 <el-footer> 时,全部子元素会垂直上下排列,否则会水平左右排列。
注:以上组件采用了 flex 布局,使用前请确定目标浏览器是否兼容。此外,<el-container>的子元素只能是后四者,后四者的父元素也只能是 <el-container>。
<el-header>:顶栏容器。
<el-aside>:侧边栏容器。
<el-main>:主要区域容器。
<el-footer>:底栏容器。
通过基础的 24 分栏,迅速简便地创建布局。
通过 row 和 col 组件,并通过 col 组件的 span 属性我们就可以自由地组合布局。
Row 组件 提供 gutter 属性来指定每一栏之间的间隔,默认间隔为 0。
通过制定 col 组件的 offset 属性可以指定分栏偏移的栏数。
排版
将 type 属性赋值为 ‘flex’,可以启用 flex 布局,并可通过 justify 属性来指定 start(左对齐), center(水平居中), end(右对齐), space-between(两端对象), space-around (每个成员两边都有间隔)其中的值来定义子元素的排版方式。
响应式布局
参照了 Bootstrap 的 响应式设计,预设了五个响应尺寸:xs 超小屏幕、sm 小屏幕、md 中等、lg大屏幕和 xl超大
<el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">
<div class="grid-content bg-purple"></div>
</el-col>
基于断点的隐藏类
Element 额外提供了一系列类名,用于在某些条件下隐藏元素。这些类名可以添加在任何 DOM 元素或自定义组件上。如果需要,请自行引入以下文件:
import ‘element-ui/lib/theme-chalk/display.css’;
包含的类名及其含义为:
hidden-xs-only - 当视口在 xs 尺寸时隐藏
hidden-sm-only - 当视口在 sm 尺寸时隐藏
hidden-sm-and-down - 当视口在 sm 及以下尺寸时隐藏
hidden-sm-and-up - 当视口在 sm 及以上尺寸时隐藏
hidden-md-only - 当视口在 md 尺寸时隐藏
hidden-md-and-down - 当视口在 md 及以下尺寸时隐藏
hidden-md-and-up - 当视口在 md 及以上尺寸时隐藏
hidden-lg-only - 当视口在 lg 尺寸时隐藏
hidden-lg-and-down - 当视口在 lg 及以下尺寸时隐藏
hidden-lg-and-up - 当视口在 lg 及以上尺寸时隐藏
hidden-xl-only - 当视口在 xl 尺寸时隐藏
button
使用type、plain、round和circle属性来定义 Button 的样式。
type: default(不写),primary,success,info, danger, warning
plain: 无背景色显示
round: 圆角
circle: 圆
侧边栏
<el-menu
default-active="/fyfs"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
:default-openeds="openeds"
ref="menus"
:router="true"
>
使用侧边栏不折叠
methods: {
handleSelect(key, keyPath) {
console.log(key, keyPath);
},
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
//1.2 设置侧边栏默认不折叠
this.$refs.menus.open(keyPath);
}
}
官方文档
更多详情参考Element
keep-alive和transition
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。 最小值是2。
当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
注意嵌套的顺序,过渡组件在最外面
<transition>
<keep-alive include="About">
<!-- 缓存组件,默认缓存所有组件: -->
<router-view />
</keep-alive>
</transition>
书写生命周期:
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created');
},
beforeMount() {
console.log('beforeMount');
},
mounted() {
console.log('Mounted');
},
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
beforeDestroy() {
console.log('beforeDestory');
},
destroyed() {
console.log('destoryed');
},
deactivated() {
console.log('deactived');
},
activated() {
console.log('actived');
},
三个框框依次是首次进入组件,切换组件,再次进入组件
如果没有缓存则这三种情况下依次打印:
首次进入组件:
切换组件:
再次进入组件:
Router编程式导航的方法
router.push()
router.replace(): 跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
router.go(n)
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)。
router.back()
router.forward()
Route路由信息对象
$route.path:字符串,对应当前路由的路径,总是解析为绝对路径,如 “/foo/bar”。
$route.params :一个 key/value 对象,包含了动态片段和全匹配片段 /user/:id
$route.query: 一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。
$route.matched:类型: Array,一个数组,包含当前路由的所有嵌套路径片段的路由记录 。路由记录就是 routes 配置数组中的对象副本 (还有在 children 数组)。
导航守卫
全局守卫
beforeEach全局前置守卫(router内)
router.beforeEach((to,from,next)=>{
//可以做导航时的验证;如登录,访问权限等;
next()
})
beforeEach和meta的使用(<eg.访问权限>)
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
// a meta field
meta: { requiresAuth: true }
}
]
})
router.beforeEach((to, from, next) => {
//to.matched包括了一级路径和二级路径,是一个数组
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!auth.loggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // 确保一定要调用 next()
}
})
Array.some((item)=>{
return 条件表达式
})
some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。
some() 方法会依次执行数组的每个元素:
如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
如果没有满足条件的元素,则返回false。
注意: some() 不会对空数组进行检测。不会改变原始数组。
before
Resolve全局解析守卫
router.beforeResolve 注册一个全局守卫。这和router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
afterEach全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身。
router.afterEach((to, from) => {
// ...
})
更改导航标题meta和afterEach
const routes = [
{
path: '/',
redirect:'/home',
meta:{requiresAuth:true,title:'首页'}
}
]
router.afterEach((to, from) => {
// console.log(to)
document.title = to.meta.title;
})
beforeEnter路由独享守卫
只在配置了的路由上,才会触发该钩子函数;
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
next()
}
}
]
})
组件内的守卫
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
next(vm => {
// 通过 `vm` 访问组件实例
})
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
路由导航的流程理解
导航被触发。(点击超链接时)
在失活的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用独享守卫 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入
Axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
安装
npm i axios --save
使用
main.js引入axios
import axios from ‘axios’
配置基路由
axios.defaults.baseURL = “http://127.0.0.1:8000/api”
全局挂载axios
Vue.prototype.$axios = axios;
发送请求:
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
// 发送 GET 请求
axios({
method: 'get',
url: '/user/12345',
params: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
实际开发使用
在实际的项目开发中,要根据JAVA后台接受的参数做调整。
GET
GET /gxa/post1?uname=aaa&uage=12
let data = {
uname: "aaa",
uage: 12,
};
this.$axios({
method: "get",
url: "/post1",
headers: { "content-type": "application/x-www-form-urlencoded" },
params:data,
})
POST
直接传递对象
后台接收到的参数: {uname: “aaa”, uage: 12}
let data = {
uname: "aaa",
uage: 12,
};
this.$axios({
method: "post",
url: "/post1",
headers: { "content-type": "application/json" },
data:data,
})
JSON.stringify处理对象后传递
后台接收:{“uname”:“aaa”,“uage”:12,“gfInfo”:{“name”:“aaa”,“sex”:0,“age”:18}}
let data = {uname: "aaa", uage: 12, gfInfo: {name: "aaa", sex: 0, age: 18}};
this.$axios({
method: "post",
url: "/post1",
headers: { "content-type": "application/json" },
data:JSON.stringify(data)
})
qs处理对象后传递序列化为字符串:%5B %5D<===>[ ]
后台接收:/gxa/post1?uname=aaa&uage=12&gfInfo%5Bname%5D=aaa&gfInfo%5Bsex%5D=0&gfInfo%5Bage%5D=18
//main.js全局引入挂载qs
import qs from 'qs'
Vue.prototype.$qs = qs
----------------------------
let data = {
uname: "aaa",
uage: 12,
};
this.$axios({
method: "post",
url: "/post1",
headers: { "content-type": "application/x-www-form-urlencoded" },
data:this.$qs.stringify(data)
})
拦截器的使用
以加载动画为案例
// 声明一个空的对象;
let loadingInstance;
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// console.log(config);
// 在发送请求之前做些什么,全屏加载
// 显示加载动画
loadingInstance = ElementUI.Loading.service({ fullscreen: true ,text:"努力加载中...","background":"rgba(0,0,0,0.5)"});
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
// 关闭动画
loadingInstance.close();
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
axios的封装
main.js配置
// 静态资源的基础路径 ,根据项目的部署方式来修改IP。
Vue.prototype.staticBaseUrl= 'http://127.0.0.1:8000'
// 导入封装了token功能 的axios实例的模块;
import axios from './http/http.js';
Vue.prototype.$axios = axios;
http/http.js配置
import Axios from "axios";
import router from './../router'
import { Loading } from 'element-ui';
// 创建一个axios实例
let http = Axios.create({
timeout: 10000,
baseURL: process.env.VUE_APP_BASE_URL
});
export default http;
let loadingInstance;
// 请求前拦截,
http.interceptors.request.use(
reqConfig => {
// console.log('请求前:', reqConfig);
// 当你登录 成功后,会在本地存储一个sessionStorage.setItem("token","sdfasfd2323"),
let token = sessionStorage.getItem('token');
// 如果有存储token,则把token添加到请求头。
// 要问一下后端token验证时,headers中是哪一个属性名;
token && (reqConfig.headers['authenticate'] = token);
// 显示加载动画
loadingInstance = Loading.service({ fullscreen: true, text: "努力加载中...", "background": "rgba(0,0,0,0.5)" });
return reqConfig
},
error => Promise.reject(error));
//响应后干什么
http.interceptors.response.use(resp => {
// console.log(resp)
//后台给我们token 存起来
// 直接把拦截器放到main.js中,多一个.data
// resp.data.data.token && sessionStorage.setItem('token',resp.data.data.token);
//封装在HTTP.JS中,就少写一个.data;
// 如果响应回来 的数据中,带有token,就把token做本地存储;自动更新token;
resp.data.token && sessionStorage.setItem('token', resp.data.token);
// 关闭动画
loadingInstance.close();
return resp
}, error => {
// error直接打出来,是错误信息的内容;
// console.log(error)
// 但是error也是 一个对象;
// console.log(error.response)
let _resp = error.response;
switch (_resp.status) {
case 401:
case 500:
// 哪些情况下,需要清除token,请自己添加case 状态码;
//把本地的token清除 跳转到login
sessionStorage.removeItem('token')
// sessionStorage.removeItem('userName')
// sessionStorage.removeItem('type')
// alert('身份已过期,请重新登录')
return router.push('/login') // 跳转到登录页面;
}
return Promise.reject(error.response.data)
});
v-slot插槽缩写#
slot:组件功能的扩展
父组件:
<ProductZhanShi title="全球预售">
<template>
预售倒计时 0天12小时2分10秒
</template>
<template v-slot:more>
<span>More</span>
</template>
</ProductZhanShi>
子组件:
<!-- 默认的插槽, 在调用子组件时,把子组件当双标签使用,标签元素的内容,默认就是传递给默认插槽的数据; -->
<!-- 一个不带 name 的 <slot> 出口会带有隐含的名字“default”。 -->
<slot></slot>
<!-- 具名的插槽 -->
<slot name="more"></slot>
插槽绑定值传给父组件
子组件:
<slot name="userInfo" :user="tempData" :age="18"></slot>
父组件:
<template v-slot:userInfo="{user, age}">
<h3>{{user.username}}</h3>
<h1>{{user.userpwd}}</h1>
<h1>{{age}}</h1>
</template>
//或者
<template #userInfo="{user, age}">
<h3>{{user.username}}</h3>
<h1>{{user.userpwd}}</h1>
<h1>{{age}}</h1>
</template>
当然也可以传递对象:
//子组件
<slot name="userInfo" :scope="{user:{}, age:18}" ></slot>
//父组件
<template #userInfo="scope">
<h3>{{scope.user.username}}</h3>
<h1>{{scope.user.userpwd}}</h1>
<h1>{{scope.age}}</h1>
</template>
跨域
后端配置了CORS跨域
前端不做代理;
开发环境下:
axios.defaults.baseURL = “http://172.16.2.34:8000/api”
打包前: 要修改axios.defaults.baseURL;
部署在JAVA环境下: axios.defaults.baseURL = "/gxa"带前缀 || ""不带前缀;
前后端分离部署:
nginx来部署前端,通过Nginx代理来请求JAVA服务器;
axios.defaults.baseURL = “/api”
代理服务器
axios.defaults.baseURL = “/api”
代理服务器,只在开发环境下有效!
设置vue.config.js文件:
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
devServer: { //开发用的服务器配置
proxy: {
// 前端/api/login =传给后台=> 后台/gxa/login
'/api': {
target: 'http://127.0.0.1:8000', //这里是目标服务器地址
changeOrigin: true, //改变源地址,必须是true,代理才有效
pathRewrite: { //路径重写
// 如果后端完整的接口名,没有/api,就替换成"",如果有,就把/api,替换成指定的前缀。
//表示把前端所有的/api换为/gxa
'^/api': '/gxa' //这里一定要为空
}
},
//代理不同的地址
'/bpi':{
target: 'http://127.0.0.1:8001',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
自动切换baseURL
添加.env.development和.env.production两个文件。
分别写入:
VUE_APP_BASE_URL=’/api’
VUE_APP_BASE_URL=’/gxa’
配置axios,所有的后台接口请求,都会带上baseURL的值做基础路径:
axios.defaults.baseURL = process.env.VUE_APP_BASE_URL
文件上传
案例上传多张图片并预览
<form name="photoList">
<div class='file'>选择文件
<input type="file" name="photo" multiple @change='getFile' class='addfile'/>
| 已选:<span v-for='(obj,index) in photoname' :key='index'>{{obj}} 🐷 </span>
</div>
</form>
<el-button type="primary" @click="mySubmit">保存图片</el-button>
getFile(){
let fileIpt = document.getElementsByName("photo")[0];
// 获取上传文件的对象的值fileIpt.files;
this.$data.photoList.files = fileIpt.files;
console.log('photoList',this.$data.photoList);
this.$data.photoname = []
for(let i =0;i<fileIpt.files.length;i++){
this.$data.photoname.push(fileIpt.files[i].name)
}
},
mySubmit() {
let formData = new FormData()
//每一个formData内的数据都要单独append
//给formData添加files对象
for(let i = 0;i<this.$data.photoList.files.length;i++){
formData.append('files',this.$data.photoList.files[i])
}
//给formData添加id值
formData.append('id',this.$data.fid)
formData.append('zhaoPianDiZhi',this.$data.zhaoPian)
console.log('formData',formData);
this.$axios({
method: "post",
url: "/fangJian/shangChuanTuPian",
//必须修改请求头,且不需要序列化
headers: { "content-type": "multipart/form-data" },
data: formData
}).then((res)=>{
console.log(res);
if(res.status==200){
console.log('上传图片成功',res);
this.$message({
message:'上传图片成功',
type:'success'
})
//页面刷新数据
this.reload()
}
})
},
页面自动刷新(如请求成功刷新页面数据)
使用provide和inject
App.vue
<template>
<div id="app">
<router-view v-if="isRouterAlive"/>
</div>
</template>
<script>
export default {
name: 'App',
provide () {
return {
reload: this.reload
}
},
data () {
return {
isRouterAlive: true
}
},
methods: {
reload () {
this.isRouterAlive = false
this.$nextTick(function () {
this.isRouterAlive = true
})
}
}
}
</script>
在要使用刷新的vue页面中:
inject:['reload'],
methods: {
mySubmit() {
this.$axios({
//...
}).then((res)=>{
if(res.status==200){
//页面刷新数据 也可以加一个setTimeout定时器
this.reload()
}
})
},
}
VueX
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
安装
npm i --save vuex
基础使用
在src下,创建一个store目录 ,再store创建一个index.js;
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//导出一个Vuex.Store 仓库的实例
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
在main.js中,引入index.js
import store from './store/index.js"
//import store from './store',//或者,默认就是找这个目录下的index.js文件。
//再把store注入Vue实例中;
new Vue({
router,
store, //可以在组件中,通过 this.$sotre拿获取Store中的状态和方法。
render: h => h(App)
}).$mount('#app')
VueX应用
dispatch传值给actions做数据存储
this.$store.dispatch(‘setAllfs’,res.data.data)
actions处理dispatch函数,提交commit给mutations
actions: {
//方式一
// setAllfs(context,obj){
// context.commit('setAllfsData',obj)
// }
//方式二
setAllfs({commit},obj){
commit('setAllfsData',obj)
}
},
mutations处理actions函数,更改state数据
state: {
allfsdata:[]
},
mutations: {
setAllfsData(state,obj){
state.allfsdata = obj
}
},
getter:Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters: {
getData(state){
return state.allfsdata
}
}
使用getters,当状态的值改变时,页面没有重选渲染,就要使用getters
<div>{{$store.getters.getData}}</div>
注:只允许在actions中的任务方法中,实现异步的逻辑代码;不允许在 mutations 中写异步的逻辑代码,因为VueTools中不能跟踪到state的改变。规范中就要求不要在mutations中写异步。
VueX映射
import {mapState,mapActions,mapGetters,mapMutations} from “vuex”
// 映射Store中的State和getters, 当本组内部的计算属性来使用;
computed:{
...mapState(['loginState','userInfo']),
...mapGetters(['_login'])
},
// 映射mutations, actions, 当本组内部的方法来使用;如果不需要传参数,就直接使用,如果要传参数,就需要单独声明一个方法,来调用映射过来的方法。
methods: {
...mapActions(['testLogin']),//指向dispatch
...mapMutations(['testAsync']),//指向commit
_testAsync(){
this.testAsync("hello") ;因为需要传参数 ,所以单独声明一个函数来调用它
},
_testLogin(){
this.$store.dispatch("testLogin")
},
}
$refs
一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。
<ShopCars ref="shopCars" :table-data="shopCars" @my-jia="myJia" @my-jian="myJian"></ShopCars>
<el-button type="success" @click="orderTrue">下订单</el-button>
orderTrue(){
//打印所有的选中项
console.log(this.$refs.shopCars.multipleSelection);
}
Bus
EventBus 主要解决非父子组件之间的通信。不适合用于大型的项目;大型项目,一般用Vuex来处理;
import Vue from ‘vue’;
let Bus = new Vue();
export default Bus;
创建bus.js
凡是要共享数据 的组件,都要引用bus.js文件;每一个Vue实例对象,都会有一个$on(),$emit()两个方法;
Bus.$on(自定义的事件名,回调函数(形参)): 监听事件
Bus.$emit(自定义的事件名, 实际参数): 触发事件
Bus.$off(自定义的事件名) : 销毁事件
$parent、$children、$root
$parent:获取当前组件的直接父组件的实例对象。可以链式写法。
$children:获取直接子组件的实例对象,如果有多个直接的子组件对象,它们的顺序是不固定的。$children返回一个数组对象。
$:当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
$attrs
<AttrSubCom :html="course.html" :css="course.css" :js="course.js" :vue="vue"></AttrSubCom>
props:["html","css"],
created() {
// 可以看到所有props声明过的属性;console.log(this.$props);//["html","css"],
// 父组件给绑定了的属性,但props中没有声明有,可以通过$attrs来获取。
console.log(this.$attrs); //{js,vue}
}