安装
文档:https://cli.vuejs.org/zh/
第一步:全局安装(仅第一次执行)
npm install -g @vue/cli
或
yarn global add @vue/cli
备注:如果出现下载缓慢:请配置npm 淘宝镜像:
npm config set registry https://registry.npm.taobao.org
安装的时候如果报错证书过期:
一:
清除npm缓存
npm cache clean --force
取消ssl验证:
npm config set strict-ssl false
之后再npm install
二:
npm config set registry http://registry.cnpmjs.org
npm config set registry http://registry.npm.taobao.org
第二步:切换到你要创建项目的目录,然后使用命令创建项目
名称不能再包含大写字母
vue create domeapp
第三步:启动项目
npm run serve
public/index.html 的代码理解
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<!-- 针对IE浏览器的一个特殊配置,含义是让IE浏览器以最高的渲染级别渲染页面 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 开启移动端的理想视口 -->
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!-- 配置页签图标 -->
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- 配置网页标题 -->
<title>哈哈系统</title>
</head>
<body>
<!-- 当浏览器不支持JS时noscript中的元素就会被渲染 -->
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<!-- 容器 -->
<div id="app"></div>
</body>
</html>
main.js render说明
/*
该文件是整个项目的入口文件
*/
//引入vue 引入的其实是运动版的vue vue.runtime.esm.js
import Vue from 'vue'
//引入APP组件 它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false
/*
关于不同版本的vue:
1.vue.js与vue.runtime.xxx.js的区别:
(1). vue.js是完整版的Vue,包含:核心功能+模板解析器。
(2). vue.runtime.xxx.js是运动版的Vue.只包含:核心功能:没有模板解析器。
2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
render函数接收到的createElement函数去指定具体内容
*/
//创建vue实例对象---vm
new Vue({
// el:'#app', 相当于.$mount('#app') 二者存一
//下面这行代码,完成了这个功能,将APP组件放入容器中
render: h => h(App), //相当于 render: createElement => createElement(App) createElement => createElement('h1','你好')
}).$mount('#app')
https://cli.vuejs.org/zh/config/#vue-config-js 文档 vue.config.js 是一个可选的配置文件 可以对脚手架进行个性化定制 可以修改webpack默认配置属性
单个单词组件名报错: error Component name “School” should always be multi-word vue/multi-word-component-names
这个错误是由 Vue.js 的 ESLint 插件生成的,插件名为 vue/multi-word-component-names。这个规则要求 Vue 组件的名称应该由多个单词组成,以避免与现有的或未来的 HTML 元素冲突。
解决方案一:在根目录下找到vue.config.js文件(如果没有则新建一个),添加下面的代码
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false, //关闭eslint校验
})
但是官方并不建议直接关闭校验,因为此方法只是编译时不报错,如果使用vscode+eslint会在文件头标红提示,所以推荐下一种方式。
解决方案二:在ESlint的配置文件eslintrc.js中(如果没有在根目录下新建一个名为**.eslintrc.js**的文件,注意!最前面有个点)将以下代码复制进去,此方案是根据文件进行关闭规则,更适用。
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
parserOptions: {
parser: '@babel/eslint-parser'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
},
overrides: [
//这里是添加的代码
{
files: ['src/components/**','src/pages/**'], // 匹配views和二级目录中的index.vue
rules: {
'vue/multi-word-component-names':"off",
} //给上面匹配的文件指定规则
},
{
//这就是匹配目录下的所有vue文件
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
],
env: {
jest: true
}
}
]
}
ref属性
1.被用来给元素或子组件注册引用信息(id的替代者)
2.应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3.使用方式
<template>
<div>
<!-- 打标识ref='xxx' -->
<h1 ref="doen">{{ title }}</h1>
<button ref="btn" @click="showDom">点我输出上方的DOM元素</button>
<School ref="sch" msg="你好"/>
</div>
</template>
<script>
//引入组件
import School from './components/School.vue'
export default {
name: 'App', //组件名
components: { //注册组件
School
},
data(){
return {
title:'你好打工'
}
},
methods:{
showDom(){
//获取this.$refs.xxx
console.log(this.$refs.doen) //真实DOM元素
console.log(this.$refs.btn)//真实DOM元素
console.log(this.$refs.sch) //School组件的实例对象(vc)
}
}
}
</script>
props配置
props是只读的,vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,
那么请复制props的内容到data中一份,然后去修改data中的数据。
父组件
<template>
<div>
<School name="李四" sex="女" :age="18" />
</div>
</template>
<script>
//引入组件
import School from './components/School.vue'
export default {
name: 'App', //组件名
components: { //注册组件
School
},
}
</script>
子组件
<template>
<div>
<h1>学生姓名:{{ name }}</h1>
<h1>学生性别:{{ sex }}</h1>
<h1>学生年龄:{{ myAge+1 }}</h1>
<button @click="updateAge">尝试修改收到的年龄</button>
</div>
</template>
<script>
export default {
name: 'School',
data(){
return{
myAge:this.age //props优先级更高
}
},
//三种写法 1.简单声明接收 接收数据
// props:['name','sex','age']
//三种写法 2.接收的同时对数据进行类型限制
// props:{
// name:String,
// sex:String,
// age:Number
// }
//三种写法 3.接收的同时对数据进行类型限制+默认值的指定+必要性的限制
props:{
name:{
type:String,//name的类型是字符串
required:true,//name是必须的
},
sex:{
type:String,//类型是字符串
required:true,//必须的
},
age:{
type:Number,//name的类型是字符串
default:99 //默认值
},
},
methods:{
updateAge(){
this.myAge++
}
}
}
</script>
mixin 混入
功能:可以把多个组件共用的配置提取成一个混入对象
第一步:定义混合
mixintest.js
export const mixin1= {
//vue里面可以写的这里都可以写
methods:{
showName(){
alert(this.name)
}
},
mounted(){
console.log('你好啊')
}
}
export const hunhe= {
//vue里面可以写的这里都可以写
data(){
return{
x:100,
y:200
}
}
}
第二步:使用混入
全局混入 所有的vc以及vm都会得到这个东西 (不推荐)
main.js
/*
该文件是整个项目的入口文件
*/
//引入vue 引入的其实是运动版的vue vue.runtime.esm.js
import Vue from 'vue'
//引入APP组件 它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false
//全局混合
//引入一个混合
import {mixin1,hunhe} from './mixintest.js'
Vue.mixin(mixin1) //挂载全局
Vue.mixin(hunhe) //挂载全局
//创建vue实例对象---vm
new Vue({
render: h => h(App),
}).$mount('#app')
组件使用
<template>
<div>
<h1 @click="showName">学校:{{ name }}</h1>
<h1>学校地址:{{ address }}</h1>
</div>
</template>
<script>
//引入一个混合
//import {mixin1,hunhe} from '../mixintest.js'
export default {
name: 'School',
data(){
return{
name:'清华',
address:'北京'
}
},
//配置混合 值是接收一个数组 和原有的数据或者方法 组合在一起可以用
//mixins:[mixin1,hunhe],
mounted(){
console.log('你好啊!!!!!!')
}
}
</script>
局部组件混入(推荐)
<template>
<div>
<h1 @click="showName">学生姓名:{{ name }}</h1>
<h1>学生性别:{{ sex }}</h1>
<h3>{{ x }}</h3>
</div>
</template>
<script>
//引入一个混合
import {mixin1,hunhe} from '../mixintest.js'
export default {
name: 'Student',
//如果和混合的数据发生冲突的时候 以自身的为主
data(){
return{
name:'张三',
sex:'男',
x:666
}
},
//配置混合 值是接收一个数组 和原有的数据或者方法 组合在一起可以用
mixins:[mixin1,hunhe]
}
</script>
插件
功能:用于增强vue
本质:包含install方法的一个对象,install的第一个参数是vue,第二个以后的参数是插件使用者传递的数据。
定义插件:plugins.js
export default {
install(Vue,x,y,z){
console.log(x,y,z)
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
//自定义全局指令
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value=binding.value
},
//指令所在元素被插入页面时
inserted(element){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value=binding.value
}
})
//定义混入
Vue.mixin({
data(){
return{
x:100,
y:200
}
}
})
//给vue原型上添加一个方法(vm和vc就都能用了)
Vue.prototype.hello=()=>{alert('你好啊')}
}
}
使用插件Vue.use()
main.js
//引入vue 引入的其实是运动版的vue vue.runtime.esm.js
import Vue from 'vue'
//引入APP组件 它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false
//引入插件
import plugins from './plugins'
//应用(使用)插件
Vue.use(plugins,1,2,3)
//创建vue实例对象---vm
new Vue({
render: h => h(App),
}).$mount('#app')
组件使用
<template>
<div>
<h1 >学校:{{ name | mySlice }}</h1>
<h1>学校地址:{{ address }}</h1>
<input type="text" v-fbind:value="address">
{{ y }}
<button @click="hello">点我测试一下hello方法</button>
</div>
</template>
<script>
export default {
name: 'School',
data(){
return{
name:'清华宝盛道吉',
address:'北京'
}
},
}
</script>
webStorage
1.存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
2.浏览器端通过Window.sessionStorage和Window.localStorage属性来实现本地存储机制
3.相关API:
1.xxxxStorage.setItem(‘key’,‘value’);
该方法接收一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
2.xxxxStorage.getItem(‘key’);
该方法接收一个键名作为参数,返回键名对应的值。
3.xxxxStorage.removeItem(‘key’);
该方法接收一个键名作为参数,并把该键名从存储中删除
4.xxxxStorage.clear();
该方法会清空存储中的所有数据
4.备注:
1.SessionStorage存储的内容会随时浏览器窗口关闭而消失
2.LocalStorage存储的内容,需要手动清除才消失
3.xxxxStorage.getItem(xxx) 如果xxx对应的value获取不到,那么getItem的返回值是null
4.JSON.parse(null)的结果依然是null
组件自定义事件
1.一种组件通信的方式,适用于:子组件===》父组件
2.适用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)
3.注意:通过this.$refs.xxx.$on('hahah',回调)绑定自定义事件,回到要么配置在methods中,要么用箭头函数,否则this指向会出问题
绑定自定义事件
解绑自定义事件
子组件1
<template>
<div>
<h3 >学校:{{ name }}</h3>
<h3>学校地址:{{ address }}</h3>
<!-- 两种写法都可以 -->
<button @click="sendSchoolName">把学校名给APP1</button>
<button @click="getSchoolName(name)">把学校名给APP2</button>
</div>
</template>
<script>
export default {
name: 'School',
data(){
return{
name:'清华',
address:'北京'
}
},
//声明接收
props:['getSchoolName'],
methods:{
sendSchoolName(){
this.getSchoolName(this.name)
}
}
}
</script>
子组件2
<template>
<div>
<h3 >学生姓名:{{ name }}</h3>
<h3>学生性别:{{ sex }}</h3>
<h4>当前求和为:{{number}}</h4>
<button @click="add">点我number++</button>
<button @click="sendStudentName">把学生名给APP</button>
<button @click="unbind">解绑haha事件</button>
<button @click="death">销毁当前Student组件的实例(vc)</button>
</div>
</template>
<script>
export default {
name: 'Student',
//如果和混合的数据发生冲突的时候 以自身的为主
data(){
return{
name:'张三',
sex:'男',
number:0
}
},
methods:{
sendStudentName(){
//触发Student组件实例身上的haha事件 $emit是一个函数
this.$emit('haha',this.name,666,888,900)
//this.$emit('hehe')
},
unbind(){
//解绑
this.$off('haha') //解绑一个自定义事件
//this.$off(['haha','hehe']) //解绑多个自定义事件 接收的是一个数组
//this.$off() //解绑所有的自定义事件
},
death(){
this.$destroy() //销毁了当前Student组件的实例(vc) 销毁后所有Student实例的自定义事件全都不凑效
},
add(){
this.number++
}
}
}
</script>
父组件
<template>
<div>
<h1>学生的姓名:{{ studentName }}</h1>
<!-- 通过父组件给子组件传递函数类型的props实现,子给父传递数据 -->
<School :getSchoolName="getSchoolName" />
<!-- 自定义事件 二种方式 -->
<!-- 通过父组件给子组件绑定一个自定义事件实现,子给父传递数据(第一种写法,使用@或v-on) -->
<!-- <Student @haha="demo" @hehe="m1" /> -->
<!--.once 只触发一次 -->
<!-- <Student @haha.once="demo" /> -->
<!-- 通过父组件给子组件绑定一个自定义事件实现,子给父传递数据(第二种写法,使用ref) -->
<!-- 想要添加原生的dom 点击事件 需要加修饰符@click.native 不然组件会认为是自定义事件-->
<Student ref="student" @click.native="show" />
</div>
</template>
<script>
//引入组件
import School from './components/School.vue'
import Student from './components/Student.vue'
export default {
name: 'App', //组件名
components: { //注册组件
School,Student
},
data(){
return{
studentName:''
}
},
methods:{
getSchoolName(name){
console.log('App收到了学校名',name)
},
// demo(name,x,y,z){
// console.log('App收到了学生名',name,x,y,z)
// },
//两种方式接收参数
demo(name,...a){
console.log('App收到了学生名',name,...a)
this.studentName=name
},
m1(){
console.log('hehe事件被触发了')
},
show(){
alert('ddd')
}
},
mounted(){
//注意:通过this.$refs.xxx.$on('hahah',回调)绑定自定义事件,回到要么配置在methods中,要么用箭头函数,否则this指向会出问题
// this.$refs.student.$on('haha',this.demo) //绑定自定义事件
this.$refs.student.$on('haha',function(name,...a){
console.log('App收到了学生名',name,...a)
//这里的this 是Student组件的实例对象
console.log(this)
this.studentName=name //普通函数 这里的this.studentName赋值不生效 因为这里的this是Student组件的实例对象 写成箭头函数就可以
}) //绑定自定义事件
//只触发一次 后面就不触发了
// this.$refs.student.$once('haha',this.demo) //绑定自定义事件(一次性)
}
}
</script>
全局事件总线(GlobalEventBus)(推荐)
1,一种组件间通信的方式,适用于任意组件间通信
2.安装全局事件总线 main.js
//引入vue 引入的其实是运动版的vue vue.runtime.esm.js
import Vue from 'vue'
//引入APP组件 它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false
//创建vue实例对象---vm
new Vue({
render: h => h(App),
beforeCreate(){
//全局事件总线
//把x当作一个傀儡 一般x叫 $bus x是便于理解
Vue.prototype.x=this //安装全局事件总线
//Vue.prototype.$bus=this //安装全局事件总线
}
}).$mount('#app')
3.使用事件总线
4.最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件
组件1
<template>
<div>
<h3 >学校:{{ name }}</h3>
<h3>学校地址:{{ address }}</h3>
</div>
</template>
<script>
export default {
name: 'School',
data(){
return{
name:'清华',
address:'北京'
}
},
mounted(){
//绑定事件
this.x.$on('hello',(data)=>{
console.log('我是School组件,收到了数据',data)
})
},
beforeDestroy(){
//解绑
this.x.$off('hello')
}
}
</script>
组件2
<template>
<div>
<h3 >学生姓名:{{ name }}</h3>
<h3>学生性别:{{ sex }}</h3>
<button @click="sendStudentName">把学生名给school组件</button>
</div>
</template>
<script>
export default {
name: 'Student',
//如果和混合的数据发生冲突的时候 以自身的为主
data(){
return{
name:'张三',
sex:'男',
}
},
methods:{
sendStudentName(){
//触发事件
this.x.$emit('hello',this.name)
}
}
}
</script>
消息订阅与发布 pubsub-js
1.一种组件间通信的方式,适用于任意组件通信
安装 npm i pubsub-js
引入 import pubsub from ‘pubsub-js’;
组件1
<template>
<div>
<h3 >学校:{{ name }}</h3>
<h3>学校地址:{{ address }}</h3>
</div>
</template>
<script>
import pubsub from 'pubsub-js';
export default {
name: 'School',
data(){
return{
name:'清华',
address:'北京'
}
},
mounted(){
//订阅消息 (绑定) 函数有2个参数 第一个是消息名,第二个才是参数
this.pubId= pubsub.subscribe('hello',(a,b)=>{
console.log(this)
console.log('有人发布了hello消息,hello消息的回调执行了',a,b)
})
},
beforeDestroy(){
//解绑 取消订阅 需要id才能取消 和定时器一样
pubsub.unsubscribe(this.pubId)
}
}
</script>
组件2
<template>
<div>
<h3 >学生姓名:{{ name }}</h3>
<h3>学生性别:{{ sex }}</h3>
<button @click="sendStudentName">把学生名给school组件</button>
</div>
</template>
<script>
import pubsub from 'pubsub-js';
export default {
name: 'Student',
//如果和混合的数据发生冲突的时候 以自身的为主
data(){
return{
name:'张三',
sex:'男',
}
},
methods:{
sendStudentName(){
//发布消息 (触发)
pubsub.publish('hello',this.name)
}
}
}
</script>
nextTick
1.语法:this.$nextTick(回调函数)
2.作用:在下一次DOM更新结束后执行其指定的回调
3.什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行
this.$nextTick(function(){
console.log(111)
})
动画transition
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<!-- 自己写的动画 -->
<!-- <h3 style="background-color: rebeccapurple;" v-show="isShow" class="come">你好</h3> -->
<!-- vue的动画组件 如果起name 了 就不能使用v了 就是hello开头 appear第一次就生效动画 -->
<transition name="hello" appear>
<h3 style="background-color: rebeccapurple;" v-show="isShow" >你好</h3>
</transition>
</div>
</template>
<script>
export default {
name: 'School',
data(){
return{
isShow:true
}
},
}
</script>
<style scoped>
/* vue的动画名称有规范 不能随便命名 进入的时候v-enter-active 如果起name 了 就不能使用v了 */
.hello-enter-active{
animation: haha 0.5s linear;
}
/* vue的动画名称有规范 不能随便命名 离开的时候v-leave-active 如果起name 了 就不能使用v了 */
.hello-leave-active{
animation: haha 0.5s linear reverse;
}
/* vue的动画名称有规范 不能随便命名 进入的时候v-enter-active */
.v-enter-active{
animation: haha 0.5s linear;
}
/* vue的动画名称有规范 不能随便命名 离开的时候v-leave-active */
.v-leave-active{
animation: haha 0.5s linear reverse;
}
.come{
animation: haha 1s;
}
/* reverse反转动画 */
.go{
animation: haha 1s reverse;
}
/* 动画写一个就可以了 可以反转动画 */
@keyframes haha {
from{
transform: translateX(-100%);
}
to{
transform: translateX(0px);
}
}
</style>
过渡
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<!-- 自己写的动画 -->
<!-- <h3 style="background-color: rebeccapurple;" v-show="isShow" class="come">你好</h3> -->
<!-- vue的动画组件 如果起name 了 就不能使用v了 就是hello开头 appear第一次就生效动画 -->
<transition name="hello" appear>
<h3 v-show="isShow" >你好</h3>
</transition>
</div>
</template>
<script>
export default {
name: 'School',
data(){
return{
isShow:true
}
},
}
</script>
<style scoped>
h3{
background-color: rebeccapurple;
/* transition: 0.5s linear; */
}
/* 进入的起点,离开的终点 */
.hello-enter,.hello-leave-to{
transform: translateX(-100%);
}
/* 进入的终点,离开的起点 */
.hello-enter-to,.hello-leave{
transform: translateX(0);
}
/* 进入时候激活的样式,离开时候激活的样式 */
.hello-enter-active,.hello-leave-active{
transition: 0.5s linear;
}
</style>
多个元素过渡 transition-group
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<!-- 自己写的动画 -->
<!-- <h3 style="background-color: rebeccapurple;" v-show="isShow" class="come">你好</h3> -->
<!-- vue的动画组件 如果起name 了 就不能使用v了 就是hello开头 appear第一次就生效动画 -->
<!-- transition-group 需要key值 -->
<transition-group name="hello" appear>
<h3 v-show="!isShow" key="1">你好</h3>
<h3 v-show="isShow" key="2">肯德基</h3>
</transition-group>
</div>
</template>
<script>
export default {
name: 'School',
data(){
return{
isShow:true
}
},
}
</script>
<style scoped>
h3{
background-color: rebeccapurple;
/* transition: 0.5s linear; */
}
/* 进入的起点,离开的终点 */
.hello-enter,.hello-leave-to{
transform: translateX(-100%);
}
/* 进入的终点,离开的起点 */
.hello-enter-to,.hello-leave{
transform: translateX(0);
}
/* 进入时候激活的样式,离开时候激活的样式 */
.hello-enter-active,.hello-leave-active{
transition: 0.5s linear;
}
</style>
第三方动画库
https://animate.style/
安装:npm inatall animate.css
引入 : import ‘animate.css’
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<!-- enter-active-class 进入的动画 leave-active-class 离开的动画 -->
<transition-group name="animate__animated animate__bounce"
appear enter-active-class="animate__swing"
leave-active-class="animate__backOutUp"
>
<h3 v-show="!isShow" key="1">家乐福</h3>
<h3 v-show="isShow" key="2">了来得及</h3>
</transition-group>
</div>
</template>
<script>
import 'animate.css'
export default {
name: 'Test',
data(){
return{
isShow:true
}
},
}
</script>
<style scoped>
h3{
background-color: rebeccapurple;
/* transition: 0.5s linear; */
}
</style>
配置代理vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
//lintOnSave:false, //关闭eslint校验 官方并不建议直接关闭校验
devServer:{ //开启代理服务器
host:'localhost',
port:8080,
https:false,
open:true,//是否自动启动到浏览器当中
proxy:{//代理
'/api':{ //匹配所有以 '/api'开头的请求路径
target:'http://127.0.0.1:7001', //代理目标的基础路径
changeOrigin:true,//用于控制请求头中的host值 不写默认也是true
pathRewrite:{ //重写路径
'^/api':''
}
},
'/foo': {
target: 'http://127.0.0.1:9000',
ws: true, //用于支持websocket 不写默认也是true
changeOrigin: true,//用于控制请求头中的host值 不写默认也是true
pathRewrite:{
'^/foo':''
}
},
}
}
})
slot插槽
1.作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件—》子组件
默认插槽
子组件
<template>
<div>
<h3>{{ title }}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
</template>
<script>
export default {
name: 'School',
props:['title']
}
</script>
父组件
<template>
<div>
<School title="活动价" >
</School>
<School title="极乐空间">
<ol>
<li>捡垃圾</li>
</ol>
</School>
</div>
</template>
<script>
//引入组件
import School from './components/School.vue'
export default {
name: 'App', //组件名
components: { //注册组件
School
},
}
</script>
具名插槽
子组件
<template>
<div>
<h6>{{ title }}分类</h6>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot name="demo">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
<slot name="test">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
</template>
<script>
export default {
name: 'School',
props:['title']
}
</script>
父组件
<template>
<div>
<School title="活动价" >
<template v-slot:demo>
<h3 slot="demo">熊警察局</h3>
</template>
<!-- 简写 需要template包裹 v-slot:test 或者#test -->
<template #test>
<h3 >放假夸大事实</h3>
</template>
</School>
<School title="极乐空间">
<!-- slot="test" 要和插槽name名称对应 -->
<ol slot="test">
<li>捡垃圾</li>
</ol>
<h5 slot="demo">金科股份</h5>
<!-- 可以追加 -->
<!-- <h5 slot="demo">金科股份</h5> -->
</School>
</div>
</template>
<script>
//引入组件
import School from './components/School.vue'
export default {
name: 'App', //组件名
components: { //注册组件
School
},
}
</script>
作用域插槽
1.理解:数据在组件的自身,但根据数据生成的结果需要组件的使用者来决定,(list数据在school组件中,
但使用数据所遍历出来的结构由APP组件决定)
子组件
<template>
<div>
<h6>{{ title }}分类</h6>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot :youxis="list" msg="hello">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
</template>
<script>
export default {
name: 'School',
props:['title'],
data(){
return {
list:['进度款','就看看','九二五']
}
}
}
</script>
父组件
<template>
<div>
<School title="活动价" >
<template slot-scope="haha">
{{ haha }}
<ul>
<li v-for="(item,index) in haha.youxis" :key="index">{{ item }}</li>
</ul>
</template>
</School>
<School title="活动价" >
<!-- 支持解构赋值 -->
<template slot-scope="{youxis}">
<!-- {{ haha }} -->
<ol>
<li v-for="(item,index) in youxis" :key="index">{{ item }}</li>
</ol>
</template>
</School>
</div>
</template>
<script>
//引入组件
import School from './components/School.vue'
export default {
name: 'App', //组件名
components: { //注册组件
School
},
}
</script>
vuex
要严格遵循版本
在2022年2月7日,vue3成为了默认版本,npm i vue,安装的直接就是vue3了,vue3成为默认版本的同时
,vuex也更新到了4版本,npm i vuex ,安装的是vuex4,vuex的4版本,只能在vue3中使用
vue2中,要用vuex的3版本 npm i vuex@3
vue3中,要用vuex的4版本
安装
npm i vuex@3
//在脚手架里面 不管import之间写了多少代码 它会优先扫描整个文件的import语句
//按照import编写顺序 全都汇总到最上方 按照顺序执行
引入main.js
//引入vue 引入的其实是运动版的vue vue.runtime.esm.js
//在脚手架里面 不管import之间写了多少代码 它会优先扫描整个文件的import语句
//按照import编写顺序 全都汇总到最上方 按照顺序执行
import Vue from 'vue'
//引入APP组件 它是所有组件的父组件
import App from './App.vue'
//引入store
import store from './store'
//关闭vue的生产提示
Vue.config.productionTip = false
//创建vue实例对象---vm
new Vue({
render: h => h(App),
store,
}).$mount('#app')
store/index.js
//该文件用于创建vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex插件
Vue.use(Vuex)
//准备actions 用于响应组件中的动作 处理业务逻辑
const actions={}
//准备mutations 用于操作数据(state) 修改数据
const mutations={}
//准备state 用于存储数据
const state={}
//创建并暴露store
export default new Vuex.Store({
actions,mutations,state
})
组件触发方法
组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)或$store.commit('mutations中的方法名',数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过action,即不写dispatch,直接编写commit
<template>
<div>
<!-- 模板里面不需要加this -->
{{ $store.state.sum }} <hr>
<!-- {{ haha }} -->
{{ sum }}
<!-- <button @click="jiajia">++</button> -->
<button @click="jiajia(n)">++</button>
<button @click="jiajia1(n)">++1</button>
<!-- <button @click="jia(n)">++1</button> -->
<!-- <button @click="JIA(n)">++</button> -->
<h3>{{$store.getters.bigSum}} 放大了10倍</h3>
<!-- <h3>{{big}} 放大了10倍</h3> -->
<h3>{{bigSum}} 放大了10倍</h3>
</div>
</template>
<script>
//引入映射属性 模版里面就可以简写了 省略掉$store.state. mapState只能生成带有state里面的代码
import { mapState,mapGetters,mapMutations,mapActions } from 'vuex';
export default {
name: 'App', //组件名
data(){
return {
n:10
}
},
computed:{
//借助mapState生成计算属性,从state中读取数据 (对象写法)
// ...mapState({
// haha:'sum'
// }),
//借助mapState生成计算属性,从state中读取数据 (数组写法)
...mapState(['sum']),
//借助mapGetters生成计算属性,从getters中读取数据 (对象写法)
// ...mapGetters({big:'bigSum'}),
//借助mapGetters生成计算属性,从getters中读取数据 (数组写法)
...mapGetters(['bigSum']),
},
methods:{
//程序员亲自写方法
// jiajia(){
// //dispatch和actions 对话
// // this.$store.dispatch('jia',this.n)
// //也可以直接commit 和mutations对话
// this.$store.commit('JIA',this.n)
// },
//简写上面的方法 this.$store.commit 模板点击事件需要传参
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations (感觉有点鸡肋)(对象写法)
...mapMutations({jiajia:'JIA'}),
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations (感觉有点鸡肋)(数组写法)
// ...mapMutations(['JIA']),
//简写上面的方法 this.$store.dispatch 模板点击事件需要传参
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions (感觉有点鸡肋)(对象写法)
...mapActions({jiajia1:'jia'}),
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions (感觉有点鸡肋)(数组写法)
// ...mapActions(['jia'])
}
}
</script>
store/index.js转换数据
当state中的数据需要经过加工后再使用时,可以使用getters加工
//该文件用于创建vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex插件
Vue.use(Vuex)
//准备actions 用于响应组件中的动作 处理业务逻辑 函数
const actions={
//两个参数 第一个参数是 迷你版的store 是 context 里面最想用的commit 如果这里用state直接修改数据 开发者工具就失效了 可以解构 第二个参数是值
jia({commit},value){
console.log('actions中的jia被调用了',commit,value)
commit('JIA',value)
}
}
//准备mutations 用于操作数据(state) 修改数据 函数
const mutations={
//两个参数 第一个参数是 state 第二个参数是值 开发规范方法名基本是大写
JIA(state,value){
console.log('mutations中的JIA被调用了',state,value)
state.sum +=value
}
}
//准备state 用于存储数据 像极了data
const state={
sum:0 //当前的和
}
//准备getters 用于将state中的数据进行加工 函数 像极了computed
const getters={
bigSum(state){
return state.sum*10
}
}
//创建并暴露store
export default new Vuex.Store({
actions,mutations,state,getters
})
vuex模块化+命名空间
目的:让代码更好维护,让多种数据分类更加明确
需要注意开启空间命名 后getters获取值的方式 以及commit推送的命名规则
store/index.js 可以区分开多个文件,这里都放入了一个文件里面
//该文件用于创建vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex插件
Vue.use(Vuex)
//模块化 求和相关的配置
const peiqi={
namespaced:true,//命名空间 写了这个之后 a的分类名才能被mapState 认识 默认值是false
//准备actions 用于响应组件中的动作 处理业务逻辑
actions:{
//两个参数 第一个参数是 迷你版的store 是 context 里面最想用的commit 如果这里用state直接修改数据 开发者工具就失效了 可以解构 第二个参数是值
jia({commit},value){
console.log('actions中的jia被调用了',commit,value)
commit('JIA',value)
}
},
//准备mutations 用于操作数据(state) 修改数据
mutations:{
//两个参数 第一个参数是 state 第二个参数是值 开发规范方法名基本是大写
JIA(state,value){
console.log('mutations中的JIA被调用了',state,value)
state.sum +=value
}
},
//准备state 用于存储数据
state:{
sum:0 //当前的和
},
getters:{
bigSum(state){
return state.sum*10
}
}
}
//模块化 人员相关的配置
const qiaozhi={
namespaced:true,//命名空间 写了这个之后 b的分类名才能被mapState 认识 默认值是false
//准备actions 用于响应组件中的动作 处理业务逻辑
actions:{},
//准备mutations 用于操作数据(state) 修改数据
mutations:{},
//准备state 用于存储数据
state:{
peronslist:[
{id:1,name:'李四',age:19},
{id:2,name:'张三',age:29},
]
},
getters:{}
}
//创建并暴露store
export default new Vuex.Store({
modules:{
a:peiqi,
b:qiaozhi
}
})
组件使用
<template>
<div>
<!-- 模板里面不需要加this -->
{{ $store.state.a.sum }} <hr>
<!-- 获取getters里面的属性值 -->
{{ $store.getters['a/bigSum'] }} <hr>
{{ sum }}
{{ bigSum}}
<button @click="jiajia1">++</button>
<button @click="jiajia(n)">++n</button>
{{ peronslist }}
</div>
</template>
<script>
import { mapState,mapMutations,mapGetters } from 'vuex';
export default {
name: 'App', //组件名
data(){
return {
n:10
}
},
computed:{
//state里面有什么 我们才拿什么 简写
...mapState('a',['sum']),
...mapState('b',['peronslist']),
...mapGetters('a',['bigSum'])
},
methods:{
//程序员亲自写方法
jiajia1(){
console.log(this.$store)
// a/JIA a模块里面的方法 前面是分类名
// this.$store.commit('a/JIA',this.n)
this.$store.dispatch('a/jia',this.n)
},
...mapMutations('a',{jiajia:'JIA'})
}
}
</script>
路由
2022年2月7日以后,vue-router的默认版本,为4版本,而且vue-router4,只能在vue3中去使用,
vue-router3才能用在vue2中去使用。
安装: npm i vue-router@3
全局路由守卫
router/index.js
//该文件专门用于创建整个应用的路由器
//引入vue-router
import VueRouter from 'vue-router'
//引入组件
import About from "../pages/About.vue";
import Home from "../pages/Home.vue";
import News from "../pages/News.vue";
import Detail from "../pages/Detail.vue";
import Message from "../pages/Message.vue";
//创建一个路由器
const router= new VueRouter({
routes:[
{
name:'guanyu', //跳转的时候可以简化路由的跳转
path:'/about',
component:About,
meta:{title:'关于'}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',//子路由不要加斜杆 加了就是画蛇添足了
component:News,
meta:{peiqi:true,title:'新闻'}
},
{
name:'xiaoxi',
path:'message',//子路由不要加斜杆 加了就是画蛇添足了
component:Message,
meta:{peiqi:true,title:'消息'},
children:[
{
name:'xiangqing',
// path:'detail',//子路由不要加斜杆 加了就是画蛇添足了 query参数
path:'detail/:id/:title',// 占位符 detail/:id/:title params参数需要这样配置
meta:{peiqi:true,title:'详情'},
component:Detail,
//props的第一种写法,值为对象(传递的是死数据),该对象中的所有key-value都会以props的形式传给Detail组件
// props:{ a:1,b:'hello' },
//props的第二种写法,值为布尔值,若布尔值为true,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
//局限性 不接收query参数
//props:true,
//props的第三种写法,值函数 query和params参数都可以 也可以解构赋值
// props($route){
// return {id:$route.params.id,title:$route.params.title}
// }
props({params:{id,title}}){
return {id,title}
}
}
]
}
]
},
]
})
//全局前置路由守卫---初始化的时候被调用,每次路由切换之前被调用
//to 要去那 from来自那 next放行
router.beforeEach((to,from,next)=>{
console.log('前置路由守卫',to,from)
//添加需要的限制条件 比如权限 to.name也行 都可以
//这样判断有点麻烦 如果是很多个就要写很多次 || ,可以自定义一个路由属性 只能往meta里面放 比如meta:{peiqi:true}, meta里面是可以让程序员自定义的属性
//if(to.path==='/home/news' || to.path ==='/home/message') 改写 if(to.meta.peiqi)
if(to.meta.peiqi){ //判断是否需要鉴权
if(localStorage.getItem('school')==='haha'){
next() //放行
}else{
alert('学校名不对,无权限查看!')
}
}else{
next() //放行
}
})
//全局后置路由守卫---初始化的时候被调用,每次路由切换之后被调用 没有next
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title=to.meta.title || '哈哈系统'
})
export default router
main.js引入
//引入vue 引入的其实是运动版的vue vue.runtime.esm.js
//在脚手架里面 不管import之间写了多少代码 它会优先扫描整个文件的import语句
//按照import编写顺序 全都汇总到最上方 按照顺序执行
import Vue from 'vue'
//引入APP组件 它是所有组件的父组件
import App from './App.vue'
//引入vue-router
import VueRouter from 'vue-router'
//引入store
import store from './store'
import router from './router'
//应用插件
Vue.use(VueRouter)
//关闭vue的生产提示
Vue.config.productionTip = false
//创建vue实例对象---vm
new Vue({
render: h => h(App),
store,
router
}).$mount('#app')
APP.vue页面使用
replace
1.作用:控制路由跳转时操作浏览器历史记录的模式
2.浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录
,路由跳转时候默认为push
3.如何开启replace模式:router-link 加上这个replace属性就行
<template>
<div>
<!-- vue中借助router-link标签实现路由的切换 replace不开启历史记录 -->
<router-link replace to="/about" active-class="act">about</router-link>
<!-- active-class路由激活样式 路由自带的 -->
<router-link replace to="/home" active-class="act">home</router-link>
<hr>
<div>
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'App', //组件名
data(){
return {
}
},
}
</script>
<style>
.act{
color: red;
}
</style>
嵌套(多级)路由
路由配置规则,使用children配置项
跳转(要写完整路径)
缓存路由组件 keep-alive
作用:让不展示的路由组件保持挂载,不被销毁
home页面
<template>
<div>
home
<hr>
<!-- vue中借助router-link标签实现路由的切换 -->
<router-link to="/home/news" active-class="act">news</router-link>
<!-- active-class路由激活样式 路由自带的 -->
<router-link to="/home/message" active-class="act">message</router-link>
<div>
<!-- 缓存路由组件 不写缓存下面所有的路由组件 include是指定包含某个 组件名称 缓存-->
<!-- 缓存多个 用数组 -->
<keep-alive :include="['News1','Message']">
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
</keep-alive>
<!-- 缓存一个 -->
<!-- <keep-alive include="News1">
<router-view></router-view>
</keep-alive> -->
</div>
</div>
</template>
<script>
export default {
name: 'Home', //组件名
beforeDestroy(){
console.log('Home组件即将被销毁了')
},
mounted(){
console.log('Home组件挂载完毕了')
}
}
</script>
路由传参 query参数
params参数
:配置路由,声明接收params参数
路由的props配置 简化接收的参数
作用:让路由组件更方便的收到参数
编程式路由导航
作用:不借助router-link实现路由跳转,让路由跳转更加灵活
主页面
<template>
<div>
message
<hr>
<ol>
<li v-for="m in messageList" :key="m.id">
<!-- 跳转路由并携带query参数,to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`" active-class="act">{{m.title}}</router-link> -->
<!-- 跳转路由并携带query参数,to的对象写法 -->
<!-- <router-link :to="{path:'/home/message/detail',query:{id:m.id,title:m.title}}" active-class="act">{{m.title}}</router-link> -->
<!-- <router-link :to="{name:'xiangqing',query:{id:m.id,title:m.title}}" active-class="act">{{m.title}}</router-link> -->
<!-- 跳转路由并携带params参数,to的字符串写法 路由需要配置 -->
<!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`" active-class="act">{{m.title}}</router-link> -->
<!-- 跳转路由并携带params参数,to的对象写法 注意:如果携带的是params参数 必须使用name 不能使用path -->
<router-link :to="{name:'xiangqing',params:{id:m.id,title:m.title}}" active-class="act">{{m.title}}</router-link>
</li>
</ol>
<button @click="pushShow">push查看</button>
<button @click="replaceShow">replace查看</button>
<div>
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'Message', //组件名
data(){
return{
messageList:[
{id:'001',title:'消息001'},
{id:'002',title:'消息002'},
{id:'003',title:'消息003'},
]
}
},
methods:{
pushShow(){
console.log(this.$router)
this.$router.push({name:'xiangqing',params:{id:'0011',title:'线进出口'}})
//后退
// this.$router.back()
// //前进
// this.$router.forward()
//往前或往后走几步 正数是前进 负数是后退 可前进也可以后退
//this.$router.go(1)
},
replaceShow(){
this.$router.replace({name:'xiangqing',params:{id:'0014',title:'健科出口'}})
}
}
}
</script>
子页面
<template>
<div>
<ul>
<!-- 接收query参数 -->
<!-- <li>消息编号:{{ $route.query.id }}</li>
<li>消息标题:{{ $route.query.title }}</li> -->
<!-- 接收params参数 -->
<li>消息编号:{{ $route.params.id }}</li>
<li>消息标题:{{ $route.params.title }}</li>
</ul>
<!--路由props配置的参数 简化了上面的写法接收数据 -->
<!-- 第一种写法 死数据 -->
<!-- <div>{{ a }} /{{ b }}</div> -->
<!-- 第二种写法 就是params传递的属性 -->
<div>{{ id }} /{{ title }}</div>
</div>
</template>
<script>
export default {
name:'Detail',
//props:['a','b'],//第一种写法 死数据
props:['id','title'],//第二种写法 就是params传递的属性
mounted(){
console.log(this.$route)
}
}
</script>
两个新的生命周期钩子
activated 路由组件被激活时触发
deactivated 路由组件失活时触发
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态
组件缓存的时候 这两个钩子很有用
<template>
<div>
<h4 :style="{opacity}">学生</h4>
<div>
复测: <input type="text">
</div>
</div>
</template>
<script>
export default {
name: 'News1', //组件名
data(){
return{
opacity:1
}
},
// beforeDestroy(){
// console.log('News组件即将被销毁了')
// clearInterval(this.timer)
// },
// mounted(){
// this.timer=setInterval(() => {
// console.log('@')
// this.opacity -=0.01
// if(this.opacity <=0) this.opacity =1
// }, 16);
// },
//激活
activated(){
console.log('News组件被激活了')
this.timer=setInterval(() => {
console.log('@')
this.opacity -=0.01
if(this.opacity <=0) this.opacity =1
}, 16);
},
//取消激活
deactivated(){
console.log('News组件失活了')
clearInterval(this.timer)
}
}
</script>
独享路由守卫
router/index.js
//该文件专门用于创建整个应用的路由器
//引入vue-router
import VueRouter from 'vue-router'
//引入组件
import About from "../pages/About.vue";
import Home from "../pages/Home.vue";
import News from "../pages/News.vue";
import Detail from "../pages/Detail.vue";
import Message from "../pages/Message.vue";
//创建一个路由器
const router= new VueRouter({
mode:'history',//不带#号 hash模式带#号 默认是hash模式
routes:[
{
name:'guanyu', //跳转的时候可以简化路由的跳转
path:'/about',
component:About,
meta:{title:'关于'}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',//子路由不要加斜杆 加了就是画蛇添足了
component:News,
meta:{peiqi:true,title:'新闻'},
//独享路由守卫 只有前置 没有后置 进入之前
beforeEnter:(to,from,next)=>{
console.log('独享路由守卫',to,from)
if(to.meta.peiqi){ //判断是否需要鉴权
if(localStorage.getItem('school')==='haha'){
next() //放行
}else{
alert('学校名不对,无权限查看!')
}
}else{
next() //放行
}
}
},
{
name:'xiaoxi',
path:'message',//子路由不要加斜杆 加了就是画蛇添足了
component:Message,
meta:{peiqi:true,title:'消息'},
children:[
{
name:'xiangqing',
// path:'detail',//子路由不要加斜杆 加了就是画蛇添足了 query参数
path:'detail/:id/:title',// 占位符 detail/:id/:title params参数需要这样配置
meta:{peiqi:true,title:'详情'},
component:Detail,
//props的第一种写法,值为对象(传递的是死数据),该对象中的所有key-value都会以props的形式传给Detail组件
// props:{ a:1,b:'hello' },
//props的第二种写法,值为布尔值,若布尔值为true,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
//局限性 不接收query参数
//props:true,
//props的第三种写法,值函数 query和params参数都可以 也可以解构赋值
// props($route){
// return {id:$route.params.id,title:$route.params.title}
// }
props({params:{id,title}}){
return {id,title}
}
}
]
}
]
},
]
})
//全局前置路由守卫---初始化的时候被调用,每次路由切换之前被调用
//to 要去那 from来自那 next放行
// router.beforeEach((to,from,next)=>{
// console.log('前置路由守卫',to,from)
// //添加需要的限制条件 比如权限 to.name也行 都可以
// //这样判断有点麻烦 如果是很多个就要写很多次 || ,可以自定义一个路由属性 只能往meta里面放 比如meta:{peiqi:true}, meta里面是可以让程序员自定义的属性
// //if(to.path==='/home/news' || to.path ==='/home/message') 改写 if(to.meta.peiqi)
// if(to.meta.peiqi){ //判断是否需要鉴权
// if(localStorage.getItem('school')==='haha'){
// next() //放行
// }else{
// alert('学校名不对,无权限查看!')
// }
// }else{
// next() //放行
// }
// })
//全局后置路由守卫---初始化的时候被调用,每次路由切换之后被调用 没有next
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title=to.meta.title || '哈哈系统'
})
export default router
组件内路由守卫
<template>
<div>
about
</div>
</template>
<script>
export default {
name: 'About', //组件名
beforeDestroy(){
console.log('About组件即将被销毁了')
},
mounted(){
console.log('About组件挂载完毕了')
},
//当路由进入之前 通过路由规则,进入该组件时被调用
beforeRouteEnter(to,from,next){
console.log('当路由进入之前',to,from,next)
if(to.meta.peiqi){ //判断是否需要鉴权
if(localStorage.getItem('school')==='haha'){
next() //放行
}else{
alert('学校名不对,无权限查看!')
}
}else{
next() //放行
}
},
//当路由离开之前 通过路由规则,离开该组件时被调用
beforeRouteLeave(to,from,next){
console.log('当路由离开之前',to,from,next)
next() //放行
}
}
</script>
安装PC端 组件库element-ui
https://element.eleme.io/#/zh-CN/component/installation
安装 npm i element-ui
按需引入 需要安装这个
npm install babel-plugin-component -D
修改babel.config.js文件内容 注意**@babel/preset-env**这个和官方的有区别
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
["@babel/preset-env", { "modules": false }]
],
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
main.js
//引入vue 引入的其实是运动版的vue vue.runtime.esm.js
//在脚手架里面 不管import之间写了多少代码 它会优先扫描整个文件的import语句
//按照import编写顺序 全都汇总到最上方 按照顺序执行
import Vue from 'vue'
//引入APP组件 它是所有组件的父组件
import App from './App.vue'
//引入vue-router
import VueRouter from 'vue-router'
//引入store
import store from './store'
import router from './router'
//按需引入
import { Button } from 'element-ui';
Vue.component(Button.name, Button);
//完整引入
//引入ElementUI组件库
// import ElementUI from 'element-ui';
// //引入ElementUI全部样式
// import 'element-ui/lib/theme-chalk/index.css';
// //应用ElementUI
// Vue.use(ElementUI);
//应用插件
Vue.use(VueRouter)
//关闭vue的生产提示
Vue.config.productionTip = false
//创建vue实例对象---vm
new Vue({
render: h => h(App),
store,
router
}).$mount('#app')