vue2 脚手架

news2024/12/23 19:02:43

安装

文档: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')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1533027.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EFcore的实体类配置

1 约定配置 约定大于配置&#xff0c;框架默认了许多实体类配置的规则&#xff0c;在约定规则不满足要求时&#xff0c;可以显示地定义规则 1 数据库表明在不指定的情况下&#xff0c;默认使用的是数据库上下文类【DBContext】中DbSet 的属性名&#xff1b; 2 数据库表列的名字…

大数据开发--02.环境准备

一.准备三台linux虚拟机 1.分别取名node1,node2,node3 2.配置静态ip 这里以node1为例&#xff0c;配置静态ip地址&#xff0c;其他node2.node3一样 配置完成之后别忘记 systemctl restart network 3.在各自的/etc/hosts文件中编辑三个Ip地址 三台都要配置&#xff0c; 4.然…

使用Dockerfile打包java项目生成镜像部署到Linux

1、Dockerfile 介绍 如果说容器就是“小板房”&#xff0c;镜像就是“样板间”。那么&#xff0c;要造出这个“样板间”&#xff0c;就必然要有一个“施工图纸”&#xff0c;由它来规定如何建造地基、铺设水电、开窗搭门等动作。这个“施工图纸”就是“Dockerfile”。 比起容…

【MySql实战--日志系统:一条SQL更新语句是如何执行的?】

前面我们系统了解了一个查询语句的执行流程&#xff0c;并介绍了执行过程中涉及的处理模块。相信你还记得&#xff0c;一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块&#xff0c;最后到达存储引擎。 那么&#xff0c;一条更新语句的执行流程又是怎…

Apache Superset

前言 最近在准备一个小的项目&#xff0c;需要对 Hive 的数据进行展示&#xff0c;所以想到了把 Hive 的数据导出到 MySQL 然后用 Superset 进行展示。 Superset 1.1 Superset概述 Apache Superset是一个现代的数据探索和可视化平台。它功能强大且十分易用&#xff0c;可对接…

基于WTR096-28SS芯片方案的宠物喂食器实现智能化喂食功能

一、简介 本方案宠物喂食器采用了WTR096-28SS芯片方案来实现智能化的喂食功能。该方案结合了先进的技术和设计理念&#xff0c;提供了便捷、智能和个性化的宠物喂食解决方案。 该宠物喂食器具备定时、定量喂食功能&#xff0c;可以根据主人设定的时间和食物量&#xff0c;自动…

AI大模型与ChatGPT:开启智慧科研新篇章丨ChatGPT在地学、GIS、气象、农业、生态、环境科学等领域应用

目录 专题一 开启大模型 专题二 基于ChatGPT大模型提问框架 专题三 基于ChatGPT大模型的论文助手 专题四 基于ChatGPT大模型的数据清洗 专题五 基于ChatGPT大模型的统计分析 专题六 基于ChatGPT的经典统计模型 专题七 基于ChatGPT大模型的机器学习 专题八 ChatGPT的二次…

stm32f103c8t6学习笔记(学习B站up江科大自化协)-ADC

ADC简介 ADC&#xff0c;英文全称是Analog to Digital Convert&#xff0c;意为模拟数字转换器&#xff0c;简称模数转换器&#xff0c;或者叫AD转换器&#xff0c;STM32主要是数字电路&#xff0c;数字电路只有高低电平&#xff0c;没有几V电压的概念&#xff0c;如果想读取电…

AI大模型额外学习一:斯坦福AI西部世界小镇笔记(包括部署和源码分析)

文章目录 一、简单介绍1&#xff09;项目代码介绍2&#xff09;重新播放模拟3&#xff09;适当修改分叉模拟 二、部署斯坦福小镇Demo1&#xff09;准备工作2&#xff09;解决遇到的bug3&#xff09;启动服务器和前端 三、源码剖析1&#xff09;主题顺序 github链接 一、简单介…

排序算法:快速排序(非递归)

文章目录 一、先建立一个栈二、代码编写 !](https://img-blog.csdnimg.cn/direct/870dd101173d4522862e4459b32237a3.png) 先赞后看&#xff0c;养成习惯&#xff01;&#xff01;&#xff01;^ _ ^<3 ❤️ ❤️ ❤️ 码字不易&#xff0c;大家的支持就是我坚持下去的动力…

鸿蒙开发之导航栏tabs(类似Android tablayout)

当页面信息较多时&#xff0c;为了让用户能够聚焦于当前显示的内容&#xff0c;需要对页面内容进行分类&#xff0c;提高页面空间利用率。Tabs组件可以在一个页面内快速实现视图内容的切换&#xff0c;一方面提升查找信息的效率&#xff0c;另一方面精简用户单次获取到的信息量…

ES的集群节点发现故障排除指南(1)

本文是ES官方文档关于集群节点发现与互联互通的问题排查指南内容。 英文原文&#xff08;官网&#xff09; 集群节点发现是首要任务 集群互连&#xff0c;重中之重&#xff01; 在大多数情况下&#xff0c;发现和选举过程会迅速完成&#xff0c;并且主节点会长时间保持当选状…

3个Tips,用“AI”开启新生活

相信最近&#xff0c;很多朋友们都回归到了忙碌的生活节奏中。生活模式的切换&#xff0c;或多或少会带来身体或情绪状况的起伏。新技术正在为人们生活的方方面面带来便利。3个小Tips或许能让你也从新技术中获益&#xff0c;从身到心&#xff0c;用“AI”开启新生活。 关”A…

【研究僧总结】回顾第1095个创作日

目录 前言一. 机缘二. 日常三. 展望 前言 感觉刚过1024不久&#xff0c;现在又来个1095创作日 一. 机缘 研究僧一直在找平台做笔记&#xff0c;方便之后的回顾总结&#xff0c;也让各位网友见证你我的成长&#xff0c;相互学习 止不住的写文止不住的成长&#xff0c;大家共同…

流畅的 Python 第二版(GPT 重译)(十二)

第五部分&#xff1a;元编程 第二十二章&#xff1a;动态属性和属性 属性的关键重要性在于&#xff0c;它们的存在使得将公共数据属性作为类的公共接口的一部分完全安全且确实可取。 Martelli、Ravenscroft 和 Holden&#xff0c;“为什么属性很重要” 在 Python 中&#xff0…

腾讯云优惠券怎么领?谁知道?分享一下

腾讯云代金券领取渠道有哪些&#xff1f;腾讯云官网可以领取、官方媒体账号可以领取代金券、完成任务可以领取代金券&#xff0c;大家也可以在腾讯云百科蹲守代金券&#xff0c;因为腾讯云代金券领取渠道比较分散&#xff0c;腾讯云百科txybk.com专注汇总优惠代金券领取页面&am…

Mysql——基础命令集合

目录 前期准备 先登录数据库 一、管理数据库 1.数据表结构解析 2.常用数据类型 3.适用所有类型的修饰符 4.使用数值型的修饰符 二、SQL语句 1.SQL语言分类 三、Mysql——Create,Show,Describe,Drop 1.创建数据库 2.查看数据库 3.切换数据库 4.创建数据表 5.查看…

Linux信号补充——信号发送和保存

三、信号的发送与保存 3.1信号的发送 ​ 必须有操作系统来保存信号&#xff0c;因为他是管理者&#xff1b; ​ 信号给进程的task_struct发送信号&#xff0c;在task_struct中维护了一个整数signal有0-31位&#xff0c;共32个bit位&#xff1b;对于信号的管理使用的是位图结…

阿里云2核4G服务器支持多少人在线?2C4G多少钱一年?

2核4G服务器支持多少人在线&#xff1f;阿里云服务器网账号下的2核4G服务器支持20人同时在线访问&#xff0c;然而应用不同、类型不同、程序效率不同实际并发数也不同&#xff0c;2核4G服务器的在线访问人数取决于多个变量因素。 阿里云2核4G服务器多少钱一年&#xff1f;2核4…

Python 深度学习第二版(GPT 重译)(三)

七、使用 Keras&#xff1a;深入探讨 本章涵盖 使用 Sequential 类、功能 API 和模型子类创建 Keras 模型 使用内置的 Keras 训练和评估循环 使用 Keras 回调函数自定义训练 使用 TensorBoard 监控训练和评估指标 从头开始编写训练和评估循环 您现在对 Keras 有了一些经…