vue2

Vue2

vue基础

什么是vue

构建用户界面的渐进式框架

渐进式框架的大概意思就是你可以只用我的一部分,而不是用了我这一点就必须用我的所有部分

MVVM

  • model 数据
  • view 页面
  • ViewModel mvvm 模式的核心,它是连接 view 和 model 的桥梁

双向数据绑定

  • 数据绑定:将后端传递的数据转化成所看到的页面
  • DOM 事件监听: 将所看到的页面转化成后端的数据

基本使用

<div id="app">
  <!-- {{也可以写表达式}} -->
  <p>{{username.toUpperCase()}}</p>
  <p>{{gender}}</p>
  <p>{{age >= 18 ? '成年' : '未成年'}}</p>
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  //实例化一个Vue对象
  const vm = new Vue({
    //element 找到元素 
    el: "#app",
    // 定义数据
    data: {
      username: 'giao',
      gender: '女'
    }
  })
</script>

vue-指令

提升DOM的渲染效率 , 一套特殊的语法

内容渲染指令 {

<div id="app">
  <p>{{username}}</p>
  <!-- 所有指令都是v-xxx="值" -->
  <!-- v-text 相当于 innerText 会覆盖原内容-->
  <p v-text="age">年龄:</p>
  <!-- v-html 相当于innerHtml 会覆盖原内容 -->
  <p v-html="sex">性别:</p>
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    data: {
      username: '张三',
      age: 20,
      sex: '<strong>男</strong>'
    }
  });
</script>

属性绑定指令 v-bind

<div id="app">
  <!-- v-bind 可以简写成 : -->
  <input type="text" v-bind:placeholder="msg">
  <img v-bind:src="url" alt="" srcset="">
  <input type="text" :placeholder="msg">
  <img :src="url" alt="" srcset="">
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    data: {
      msg: '请输入一个数',
      url: 'http://www.itcbc.com:3006/formdata/laoduan.jpg ',
    }
  });
</script>

事件绑定指令 v-on

<div id="app">
  <!-- 绑定事件方法一 -->
  <div v-on:mouseenter="fn1" v-on:mouseleave="fn2" style="background: red;">hello Word</div>
  <!-- 绑定事件方法二 -->
  <div @mouseenter="fn1" @mouseleave="fn2" style="background: red;">hello Word</div>
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    //vue所有的数据,写到data里面
    data: {

    },
    //vue所有的方法都写到methods
    methods: {
      //方法可以省略:function 直接写 方法名 () {}
      fn1() {
        console.log('移入');
      },
      fn2() {
        console.log('移出');
      }
    }
  });
</script>

$event

<div id="app">
  <!-- 调用事件处理函数  不传参 -->
  <button @click="dianji1">不传参</button>

  <!-- 调用事件处理函数  传参  加括号-->
  <button @click="dianji2(123)">传参</button>

  <!-- 使用事件对象 $event表示事件对象 -->
  <button @click="dianji3(123,$event)">传参</button>
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    methods: {
      dianji1 (){
        console.log('val');
      },
      dianji2 (val){
        console.log(val);
      },
      dianji3 (val,e){
        console.log(val,e);
        //target 事件对象
        e.target.style.background = 'red'
      },
    }
  });   
</script>

修饰符

<div id="app">
  <a href="https://www.baidu.com">点击跳转</a>
  <form action="" method="get">
    <input type="text">
    <!-- 阻止默认事件 -->
    <button @click.prevent="dianji">提交</button>


  </form>

  <!-- 查找回车 -->
  <!-- 如果不用键名用keyCode数字也可以 -->
  <input type="text" @keyup.enter="huiche" placeholder="按回车">
  <input type="text" @keyup.49="huiche" placeholder="按1">
  <input type="text" @keyup.a="huiche" placeholder="按a">

  <!-- 阻止冒泡 -->
  <div style="width: 200px; height: 200px; background: #000;" @click="father">
    <div style="width: 100px; height: 100px; background: rgb(255, 0, 0);" @click.stop="son"></div>
  </div>


</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    methods: {
      dianji() {
        console.log('111');
      },
      huiche() {
        console.log('1');
      },
      father() {
        console.log('father');
      },
      son() {
        console.log('son');
      }
    }
  });   
</script>

双向绑定指令 v-model

  • 不操作dom的前提下 修改数据
  • .trim 处理首尾空格
  • .lazy 改变时更新
  • .number 只能输入数字
<div id="app">
  <form action="" method="get">
    姓名:<input type="text" v-model.trim="username"><br>
    <input type="radio" value="男" v-model="sex">男
    <input type="radio" value="女" v-model="sex">女<br>
    <input type="checkbox" value="抽烟" v-model="hobby">抽烟
    <input type="checkbox" value="喝酒" v-model="hobby">喝酒<br>
    <select name="" id="" v-model="address">
      <option value="北京">北京</option>
      <option value="天津">天津</option>
      <option value="上海">上海</option>
    </select>
  </form>

</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    data: {
      username: '张三',
      sex: '男',
      hobby: ['抽烟','喝酒'],
      address: '天津'
    },
    methods: {

    }
  });   
</script>

条件渲染指令 v-if v-show

v-if和v-show

  <div id="app">
    <!-- v-if隐藏      元素会被移出 -->
    <p v-if="flag">v-if使用</p>
    <!-- v-show隐藏    元素会被隐藏     -->
    <p v-show="flag">v-show<使用/p>
  </div>

  <script src="./js/vue-2.6.12.js"></script>

      <script>
        let vm = new Vue({
          el: '#app',
          data: {
            flag: true,
          },
          methods: {

          }
        });   
      </script>

v-if-else

<div id="app">
  <p v-if="age < 18">青年</p>
  <p v-else-if="age < 30">中年</p>
  <p v-else-if="age < 60">老年</p>
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    data: {
      flag: true,
      age:50,
    },
    methods: {

    }
  });   
</script>

列表渲染指令 v-for

v-for

  • v-else-if 指令必须配合 v-if 指令一起使用,否则它将不会被识别!
  • v-for="(item,index) in arr"
    • item 每一项
    • index 下标
    • arr要循环的数组
<div id="app">
  <ul>
    <!-- :key一定要加 , 不能重复 只能是字符串数字 建议id -->
            <li v-for="(item,index) in arr" :key="item.id"> <input type="checkbox"> 索引:{{index}} id:{{item.id}} name:{{item.name}}</li>
  </ul>
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    data: {
      arr: [
        {id:1,name:"giao1",age:12},
        {id:2,name:"giao2",age:16},
        {id:3,name:"giao3",age:18}
      ]
    }
  });   
</script>

v-for简单操作

<div id="app">
  <form action="" method="get">
    <input type="text" v-model="name">
    <button @click.prevent="add">按钮</button>
  </form>
  <ul>
    <li v-for="(item,index) in arr">索引:{{index}} id:{{item.id}} name:{{item.name}}</li>
  </ul>
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>
  let vm = new Vue({
    el: '#app',
    data: {
      arr: [
        {id:1,name:"giao1",age:12},
        {id:2,name:"giao2",age:16},
        {id:3,name:"giao3",age:18}
      ],
      name: '',
      nextId: 0
    },
    methods: {
      add() {
        let ids = this.arr.map(item => item.id);
        this.nextId = Math.max(...ids) + 1;
        //this.nextId = this.arr[this.arr.length - 1].id + 1;
        this.arr.push({id: this.nextId ,name: this.name});
        this.name = '';
      }
    }
  });   
</script>

过滤器

  • 只在1 2版本 3版本剔除
<div id="app">
  <p>{{username | ucfist}}</p>
  <p>{{time | dataFormat('YYYY-MM-DD HH:mm:ss')}}</p>
</div>
<hr>
<div id="app2">
  <p>{{time | dataFormat('YYYY-MM-DD HH:mm:ss')}}</p>
</div>

<script src="./js/vue-2.6.12.js"></script>
<script src="./js/dayjs.min.js"></script>

<script>



  let vm2 = new Vue({
    el: '#app2',
    data: {
      username: 'zhangsan',
      time: new Date()
    },
  })

  //设置全局变量
  Vue.filter('dataFormat', (t, g) => {
    return dayjs(t).format(g);
  })

  let vm = new Vue({
    el: '#app',
    data: {
      username: 'zhangsan',
      time: new Date()
    },
    filters: {
      ucfist(str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
      },
      //第一个参数表 | 前的值   其他参数从第二个起
      dataFormat(t, g) {
        return dayjs(t).format(g);
      }
    }
  });
</script>

watch监听器

  • 监听数据变化 从而针对数据的变化
<div id="app">
  <input type="text" v-model="username">
</div>

<script src="./js/vue-2.6.12.js"></script>

<script>

  let vm = new Vue({
    el: '#app',
    data: {
      username: '',
      age: 12
    },
    //监听器  
    watch: {
      //只要数据发生变化  调用
      username(newVal,oldVal) {
        console.log(newVal,newVal);
      }
    }
  });
</script>

判断用户名是否可用

<div id="app">
  <input type="text" v-model="username">
</div>

<script src="./js/vue-2.6.12.js"></script>
<script src="./js/axios.js"></script>

<script>
  const vm = new Vue({

    el: '#app',
    data : {
      username: ''
    },
    watch: {
      username(xin) {
        axios.get('https://www.escook.cn/api/finduser/' + xin).then(res => {
          console.log(res.data);
        })
      }
    }
  })
</script>

侦听对象

let vm = new Vue({
  el: '#app',
  data: {
    user: {
      name: '张三',
      age: 12,
      sex: '男',
    },
  },

  watch: {
    //侦听的不是一个值  是属性
    //不会触发选择器
    //只有给this.user = 新值 才会触发侦听器
    // user(xin) {
    //     console.log(xin.name);
    // }

    //解决方案1
    // 'user.name'(newVal) {
    //     console.log(newVal);
    // },

    //解决方案2
    user: {
      //固定写法
      handler(newVal) {  
        //监听对象所有 .
        console.log(newVal.name);
      },
      //加入该项可以监听对象属性
      deep: true ,
      // 页面打开马上侦听
      immediate: true
    }
  }

});

去掉温馨提示

// 去掉温馨提示     
Vue.config.productionTip = false;

vm.$mount("#app");  //找元素app

计算属性

<div id="app">
  姓:<input type="text" v-model="xing">
  名:<input type="text" v-model="ming">
  <p>您的姓名: {{xing + ming}}</p>
  <p>您的姓名: {{ fullName }}</p>
</div>

<script src="./js/vue-2.6.12.js"></script>
<script src="./js/dayjs.min.js"></script>

<script>

  // 去掉温馨提示     
  Vue.config.productionTip = false;

  let vm = new Vue({
    el: '#app',
    data: {
      xing: '',
      ming: ''
    },
    computed: {

      //fullName 就是一个计算属性
      //返回值就是计算结果
      fullName() {
        return this.xing + this.ming
      }
    }

  });
</script>

计算商品数量和总价

<div id="app">
  <ul>
    <li v-for="item in arr" ::key="item.id">商品名:{{item.name}} 单价:{{item.price}} 数量"{{item.count}}</li>
  </ul>
  <p>商品总数: {{ counts }}</p>
  <p>商品总价: {{ total }}</p>
</div>

<script src="./js/vue-2.6.12.js"></script>
<script src="./js/dayjs.min.js"></script>

<script>

  // JavaScript求和
  // let arr = [
  //     { id: 1, name: '芒果', price: 5, count: 10 },
  //     { id: 2, name: '榴莲', price: 2, count: 6 },
  //     { id: 3, name: '西瓜', price: 4, count: 3 },
  // ];
  // let res = arr.reduce((total, item) => {
  //     //总数量
  //     // return total + item.count;
  //     //总价格
  //     return total + item.price * item.count;
  // }, 0)
  // console.log(res);


  // 去掉温馨提示     
  Vue.config.productionTip = false;

  let vm = new Vue({
    el: '#app',
    data: {
      arr: [
        { id: 1, name: '芒果', price: 5, count: 10 },
        { id: 2, name: '榴莲', price: 2, count: 6 },
        { id: 3, name: '西瓜', price: 4, count: 3 },
      ]
    },
    computed: {

      //fullName 就是一个计算属性
      //返回值就是计算结果
      counts() {
        return this.arr.reduce((total,item) => total + item.count,0);
      },
      total() {
        return this.arr.reduce((total,item) => total + item.count * item.price,0);
      }
    }

  });
</script>

单页面程序

网页只有一个HTML所有功能与交互都在一个界面完成

vue-cli

简化了webpack工程创建

# npm上的一个全局包
npm install -g @vue/cli
# 快速创建  
vue create 项目名

vue组件化

把重用的ui组件化

  • template
    • 只能有一个根元素
    • 其他元素只能是这个元素的子元素
    • 不会被渲染成真正的dom元素
  • script
    • JavaScript
    • 组件相关的data methods
    • 写js 必须写 export default {}
    • data须是函数 data(){}
  • style
    • 样式
    • 支持less语法

体验

<template>
  <div id="app">
    <h1>文档第一个vue项目</h1>
    <p>我的年龄: {{ age }}</p>
    <button @click="add">qwe</button>
  </div>
</template>

<script>
 // 写js 必须写     export default {}
export default {
  //data须是函数  data(){}
  data() {
    return {
      age: 12
    }
  },
  methods: {
    add() {
      this.age++
    }
  }
}
</script>

修改vue配置

  • 创建vue.config.js 文件

  • module.exports = {
        devServer: {
            //端口
            port: 9000,
            //自动打开
            open:true
        }
    }
    

注册组件

// 使用import 导入组件 
import Left from './components/Left.vue'
// components 注册节点组件 
components: {
 Left: Left,
}
<!--以标签形式填入-->
<template>
 <Left></Left>
</template>

样式穿透

//加scoped  之后样式只对当前页面有影响
<style  scoped></style>

//css 父元素 >>> 子元素 {}
<style  scoped>
#app  >>> h2 {
  color: red;
}
</style>

//less 设置语言 /deep/ 元素 {}
//需要安装  npm i less-loader@7.3.0 -D
<style  scoped lang="less">
/deep/ h2 {
  color: red;
}
</style>

//scss 设置语言 ::v-deep 元素 {}
//需要安装  npm i sass-loader@10 sass -D
<style  scoped lang="scss">
::v-deep h2 {
  color: red;
}
</style>

全局变量

import Article from './components/Article.vue'
Vue.component('Article',Article)

组件的声明周期

生命周期

一个组件的 创建 运行 销毁 , 强调的是一个时间段

四大阶段,八大方法

  • 初始化 beforeCreate created
  • 挂载 beforeMount mounted
  • 更新 beforeUpdate updated
  • 销毁 beforeDestroy destroyed

new vue() 实例化对象

先初始化事件和生命周期函数

执行beforeCreate , 还没有初始化数据 此时不能访问data 和menthods

内部添加 data methods 的 数据

执行created 这里可以访问 data methods 可以获取数据

编译模板 : 是否有 el选项 有向下编译 没有停止生命周期

​ 有el之后 判断是否有template

​ 有 会将其变异成 render函数

​ 没有 会将外部的html作为模板编译

执行beforeMount 此时 数据还没挂载到页面

执行 mounted 函数 此时实例挂载dom 可以获取真实dom $ref

组件数据更新时 调用 beforeUpdate 数据更新了 但页面没更新

执行updated 页面更新

组件销毁时 执行beforeDestroy 此时 实例完全可以用

执行destroyed 销毁完成

组件数据共享

父传子

父元素值改变 子元素值也改变

<!--父-->
<div id="app">
 <!-- 给子组件 属性=值 就是传数据 -->
 <!-- 属性前没有冒号就是单纯的传字符串 -->
 <!-- 动态属性(:xx="")  传表达式值 -->
 <Left name="username" :newName="username" :obj='obj'></Left>  </div>
<script>
 export default {
   data() {
     return {
       username: '张三',
       obj: {
         a: 1,
         b: 2,
       }
     }
   }
 }
</script>

<!--子-->
<template>
 <div class="box">
   <h2>giao</h2>
   <p>name: {{ name }}</p>
   <p>newName: {{ newName }}</p>
   <p>obj: {{ obj.a }}</p>
   <Article></Article>
 </div>
</template>

<script>
 export default {
   //使用props接收父组件数据
   //props可以写成数组(简单) ,对象(复杂)
   //props中的值是不可以修改的  改的话只能在data赋值改
   // props: ['name','newName','obj']
   props: {
     name: {
       //设置默认值  如果没传值  用默认
       default: 'user',
       //default: () => ({}), //如果是数组或对象必须写成函数
       //类型约束  可以设置多个约束 Number String Boolean Array Object
       type: String ,
       //必须传值
       required: true
     },
     newName: {},
     obj: {}
   }
 }
</script>

子传父

父元素接收的数据与子元素互不影响

重新发送 重新接收

<!--子-->
<!--调用abc函数-->
<button @click="abc">传值</button>
<script>
 export default {
   data() {
     return {
       username: '张三',
       obj: {
         a: 1,
         b: 2,
       }
     }
   },
   methods: {
     abc() {
       //调用 $emit() 来发送数据
       // this.$emit('事件名','值','值')
       this.$emit('passVal',this.username,this.obj)
     }
   }
 }
</script>

<!--父-->
<p>{{name}}</p>
<p>{{obj.a}}</p>
<!--调用子 事件 把值传给函数--> 
<Left @passVal='getVal'></Left>  

<script>
 export default {
   data() {
     return{
       name : '',
       obj: {}
     }
   },
   methods: {
     //接收函数  接收的值和事件穿过来的值相对
     getVal(name,obj){
       this.name = name 
       this.obj = obj
       console.log(name,obj);
     }
   }

 }
</script>

ref引用

在不依赖jQuery的情况下,操作dom元素

 <h1 ref="h1">giao</h1>
 <Left ref="left"></Left>  
 <script>
   //页面渲染完触发
   mounted() {
     this.$refs.h1.style.color = 'red';
     //还可以调用组件的  方法  数据data
     this.$refs.left.abc();
     this.$refs.left.obj.a = 2;
   }
 </script>

更新数据 调用

<template>
    <div class="box">
        <h2>giao</h2> 
        <input ref="ipt" v-if="flag" type="text" @blur="showBtn" >
        <button v-else @click="showIpt">按钮</button>

    </div>
</template>

<script>
export default {
    data() {
        return {
            flag: true,
        }
    },
    methods: {
        showIpt() {
            this.flag = true;
            //下一次数据更新循环 dom渲染完之后执行
            // this.$nextTick(() => {
            //     this.$refs.ipt.focus();
            // })
        },
        showBtn() {
            this.flag = false;
        }
    },
    //页面改变 数据改变  就会执行
    //找不到输入框就报错
    updated() {
        if(this.$refs.ipt) {
            this.$refs.ipt.focus();
        }
    }
}
</script>

短路运算

// &&
true && false  // false
false && true  // false
true && true   // true

动态类名

<!--如果flag是true 显示类名3-->
<h1 :class="['类名1','类名2',flag ? '类名3 : ']">
  xxxxx
</h1>

注册Vue的插件

//注册vue组件
let user = {name: 'giao',age:20}
// 对象格式注册
// Vue.use({
	// vue.js插件应该暴露install方法
//   install(Vue){
//     //就是给Vue原型添加自定义属性
//     Vue.prototype.lt = user;
//   }
// });
//函数注册格式
Vue.use((Vue) => {
  Vue.prototype.lt = user;
});


//调用
console.log(this.lt.name)

在项目中使用axios

//安装  npm i --save axios vue-axios
//导入
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios,axios);

//调用即可
this.axios({}).then(fn);

vue 使用 echarts

npm i echarts

导入echarts 需要点击按下导入 因为 echarts 太大了

import * as echarts from 'echarts/core'
import { GridComponent } from 'echarts/components'
import { LineChart } from 'echarts/charts'
import { UniversalTransition } from 'echarts/features'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([GridComponent, LineChart, CanvasRenderer, UniversalTransition])

//导出  echarts
export default {
    install(Vue){
        Vue.prototype.echarts = echarts;
    }
}

//注册全局
import echarts_config from './utlis/echarts_config';
Vue.use(echarts_config);

this.echarts //调用

slot插槽

  • 使用插槽 必须是父子组件
  • v-slot 不可再标签使用 只能在template使用
  • slot 有默认名字 default
<!--子组件-->
<template>
    <div class="box">
        <slot name="title">
            <h2>具名插槽 有名字</h2>
        </slot>
        <slot>
            <h2>默认插槽  名字默认default</h2>
        </slot>
        <slot name="count" a="giao">
            <h2>作用域插槽</h2>
        </slot>
    </div>
</template>
<!--父组件-->
<template>
  <div id="app">
    <Left>
      <template v-slot:title>
        <h2 >对应 具名插槽</h2>  
      </template>  
	  <template>
        <h2 >对应 默认插槽</h2>  
      </template> 
	  <template v-slot:count="obj">
        <h2 >作用域slot{{obj.a}}</h2>  
      </template>
    </Left>  
  </div>
</template>

动态组件

  • 当组件设置缓存时
  • 会触发两个周期函数
    • activated 激活时触发
    • deactivated 当组件缓存 触发
<template>
  <div id="app">
    <h1 ref="h1">giao</h1>
    <!-- <Left ref="left"></Left>   -->
    <!--可以切换 cName=必须是组件-->
    <button @click="cName='Left'">Left</button>
    <button @click="cName='Left_copy'">123</button>
    <!-- 缓存标签 -->
    <!-- keep-active 里可以控制缓存组件 -->
    <keep-alive include="Left,Right"> <!--控制两个组件-->
      <!--引入组件-->
      <component :is="cName"></component>
    </keep-alive>
  </div>
</template>
<script>
import Left from './components/Left.vue'
import Left_copy from './components/Left copy.vue'
export default {
  data() {
    return {
      //需要给组件设置变量
      cName: 'Left'
    }
  },
  components: {
    Left: Left,
    Left_copy:Left_copy
  },
</script>

全局自定义指令

//全局自定义指令
// Vue.directive('指令名(不能v-)',{配置项});
Vue.directive('color',{
  //函数名固定 第一次解析标签执行
  //bind 的参数  el  指当前元素
  //obj.value  就是指令传过来的值
  bind(el,obj){
    el.style.color = obj.vule
  },
  //更新组件的时候触发
  update(el,obj){
    el.style.color = obj.vule
  },
});

//如果bind 和 update 一样可以简化代码
Vue.directive('color' ,(el,obj){
  el.style.color = obj.vule
},)

//调用 <p v-color="red">gioa</p>  data(){return{red:green}}

URL与Hash

前端路由

  • 访问不同的Hash 地址 会显示不同的组件
  • SPA指单页面
  • 不同组件切换都要依赖前端路由完成

路由工作原理

① 用户点击了页面上的路由链接
② 导致了 URL 地址栏中的 Hash 值发生了变化
③ 前端路由监听了到 Hash 地址的变化
④ 前端路由把当前 Hash 地址对应的组件渲染都浏览器中

简单实现路由

data() {
  return {
    comName: 'Home'
  }
},  
created() {
    //注册window的onhashchange事件  当hash地址变化触发事件
    window.onhashchange = () => {
      console.log(location.hash); //获取hash地址
      let hash = location.hash;
      this.comName = (hash == '#/home' ) ? 'Home' : 
                     (hash == '#/movie') ? 'Movie' :
                     (hash == '#/about') ? 'About' : '';
    }
}

//html
<a href="#/home">首页</a>
<a href="#/movie">电影</a>
<a href="#/about">关于</a>
<component :is="comName"></component>

vue-router

安装路由 npm i vue-router@3.5.2

创建路由 在src 创建 router/index.js

//导入vue和router 
import Vue from "vue";
import VueRouter from 'vue-router';

//调用 vue.use函数  把VueRouter 安装成vue插件
Vue.use(VueRouter)

//创建路由实例对象
const router = new VueRouter();

//共享路由实例
export default router 
  • 导入挂载路由 在main.js
import router from './router'
new Vue({
  render: h => h(App),
  //挂载 路由 
  router: router
}).$mount('#app')
  • 声明路由 和 占位符
<template>
  <div class="app-container">
    <h1>App 根组件</h1>
    <!-- 定义路由 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/movie">电影</router-link>
    <router-link to="/about">关于</router-link>
    <hr />
    <!-- 定义占位符 -->
    <router-view></router-view>
  </div>
</template>
  • 声明匹配规则
import Home from '../components/Home.vue'
import Movie from '../components/Movie.vue'
import About from '../components/About.vue'

//调用 vue.use函数  把VueRouter 安装成vue插件
Vue.use(VueRouter)

//创建路由实例对象
const router = new VueRouter({
    routes: [
        // 在数组中匹配规则
        {path: '/home',component: Home},
        {path: '/movie',component: Movie},
        {path: '/about',component: About}
    ]
});

重定向

//redirect 重定向
{path: '/' , redirect: '/home'},

嵌套路由

<template>
  <div class="about-container">
    <h3>About 组件</h3>
    <!-- 设置超链接 -->
    <router-link to="/about/tab1">tab1</router-link>
    <router-link to="/about/tab2">tab2</router-link>
    <!-- 占位符 -->
    <router-view></router-view>
  </div>
</template>
  • index.js
//index.js

import Tab1 from '../components/tabs/Tab1.vue'
import Tab2 from '../components/tabs/Tab2.vue'

//创建路由实例对象
const router = new VueRouter({
    routes: [
        {path: '/about',component: About, children: [
            //{path:hash地址 , component: 组件}
            //path值不能加斜杠
            {path: 'tab1' , component: Tab1},
            {path: 'tab2' , component: Tab2},

        ]},
    ]
});

动态路由

<template>
  <div class="app-container">
    <h1>App2 组件</h1>
    <router-link to="/movie/1/复联">复联</router-link>
    <router-link to="/movie/2/长津湖">长津湖</router-link>
    <router-link to="/movie/3/giao">giao</router-link>
    <hr />
    <router-view></router-view>
  </div>
</template>

<!--占位 里数据-->
<template>
  <div class="movie-container">
    <h3>Movie 组件</h3>
    <!-- 输出路由参数  $route  路由的参数 -->
    <p>电影:{{$route.params.name}}</p>
    <p>ID值:{{$route.params.id}}</p>
  </div>
</template>
  • index.js
//创建路由实例对象
const router = new VueRouter({
    routes: [
        //接收数据
        {path: '/movie/:id/:name',component: Movie}
    ]
});

使用 props 接收参数

<template>
  <div class="movie-container">
    <h3>Movie 组件</h3>
    <!-- 输出路由参数  $route  路由的参数 -->
    <p>电影:{{name}}</p>
    <p>ID值:{{id}}</p>
  </div>
</template>

<script>
export default {
  name: 'Movie',
  props: ['id','name']
}
</script>
  • index.js
//创建路由实例对象
const router = new VueRouter({
    routes: [
        //props: true  表示接收动态的id和name
        {path: '/movie/:id/:name',component: Movie,props:true}
    ]
});

vue-router 导航API

  • this.$router.push('hash地址');
    • 跳转地址并 增加一条历史记录
  • this.$router.go('数值')
    • 实现导航历史前进后退
    • -1 后退 1前进
methods: {
    back() {
      this.$router.go(-1);
    }
 }
methods: {
    tiao(){
      this.$router.push('/about')
    }
 }

全局前置守卫

  • 判断有没有token
  • 在创建路由实例对象后
//全局前置守卫  发生跳转触发
router.beforeEach((to,from,next) => {
    //to 即将跳转
    //to.path 表示跳转的地址
    //from  表示当前页
    //next() 函数 是否放行
    if(to.path == '/login'){
        next()
    }else{ 
        //判断是否登录
        if (localStorage.getItem('token')) {
            next()
        } else {
            next('/login');
        }
    }
})

懒加载

//导入的组件  如果一下子全部加载影响性能  在这里临时加载
// import Login from '@/components/MyLogin.vue'

//实例VueRouter对象
const router = new VueRouter({
    routes: [
        //这里写规则  对应的组件会放到App.vue占位符
        //懒加载  component 后面写箭头函数  返回import('@/components/MyLogin.vue')
        {path: '/login',component: () => import('@/components/MyLogin.vue')},
    ]
});

Vuex

vuex简介

  • 实现大范围数据共享
  • 能够方便,高效的数据共享
  • 数据存取一步到位
  • 数据流动非常清晰
  • 数据驱动视图

安装

npm i vuex@3.6.2

Store创建

创建store/index.js

//导入vue
import Vue from "vue";
//导入vuex
import Vuex from 'vuex'
// 注册插件
Vue.use(Vuex);
// 创建store对象
const store = new Vuex.Store({});
//导出向外共享的store对象
export default store

main.js

//导入store
import store from './store'

new Vue({
 render: h => h(App),
 //挂载
 store,
}).$mount('#app')
<p>count 值:{{$store.state.count}}</p>

mapState方法

<template>
  <div class="left-container">
    <p>count 值:{{ count }}</p>
  </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: 'Left',
  //计算属性  一定写在计算属性中
  computed: {
    ...mapState(['count','name'])
  }
}
</script>

展开运算符

//展开运算符
// ...  展开数组
// ...[1,2,3]   //1,2,3
// ...'hello'   //'h','e','l','l','o'
/*
  let arr1 = [1,2,3];
  let arr2 = [4,5,6];
  let arr3 = [...arr1,...arr2]  
*/
/*
  let obj1 = {name: 'zs', age:20};
  let obj2 = {sex:'男',height:'180cm'};
  let obj3 = [...arr1,...arr2]  
*/

store严格模式

  • 防止误修改数据
  • 想要修改需要在用Mutation
// 创建store对象
const store = new Vuex.Store({
    //开启严格模式
    strict: true,
    //全局共享数据
    state : {
        count: 100,
        name: '张三'
    },
});

Mutation

专门修改Store中的数据

只能写同步任务

// 创建store对象
const store = new Vuex.Store({
 //只能写同步代码  
 mutations: {
   //修改数据只能通过mutations
   //这里的方法  第一个参数 都是state
   changeCount(state,n) {
     state.count ++;
   }
 }
});
<!-- $store.commit('方法名',参数,参数) 调用 mutation -->
<button class="btn btn-primary" @click="$store.commit('changeCount',2)">+1</button>

mapMutations

<template>
  <div class="left-container">
    <p>count 值:{{ count }}</p>
    <button class="btn btn-primary" @click="changeCount(2)">+1</button>
  </div>
</template>

<script>
//导入
import { mapMutations } from 'vuex'

export default {
  name: 'Left',
  //计算属性
  computed: {
    //写在computed里
    ...mapState(['count','name']),
  },
  
  methods: {
    //写在methods里
    ...mapMutations(['changeCount'])
  }
}
</script>

Actions

写异步任务

// 创建store对象
const store = new Vuex.Store({
    mutations: {
        //修改数据只能通过mutations
        //这里的方法  第一个参数 都是state
        //只能写同步代码
        changeCount(state,n=1) {
            state.count += n;
        }
    },
    //异步操作 
    actions: {
        gaiCount(ctx) {
            setTimeout(() => {
                // ctx.state.count = 150;  修改数据只能在mutations
                ctx.commit('changeCount')
            },1000);
        }
    }
});
<button @click="$store.dispatch('gaiCount')">+1actions</button>

mapActions

<template>
  <div class="left-container">
    <p>count 值:{{ count }}</p>
    <button class="btn btn-primary" @click="gaiCount">+1</button>
  </div>
</template>

<script>
//导入
import { mapState,mapActions } from 'vuex'

export default {
  name: 'Left',
  //计算属性
  computed: {
    //写在computed里
    ...mapState(['count','name']),
  },
  
  methods: {
    //写在methods里
    ...mapActions(['gaiCount'])
    
  }
}
</script>

Getters

计算属性

// 创建store对象
const store = new Vuex.Store({
    getters: {
        heCount(state) {
            return state.count + state.count;
        }
    }
});
<button @click="$store.getters.heCount">getters</button>

mapGetters

<template>
  <p>count 值:{{ count }} {{heCount}}</p>
</template>

<script>
import { mapState,mapMutations,mapActions,mapGetters } from 'vuex'

export default {
  name: 'Left',
  //计算属性
  computed: {
    //这两个写到computed
    ...mapState(['count','name']),
    ...mapGetters(['heCount'])
  },
  methods: {
    //这两个写到methods
    ...mapMutations(['changeCount']),
    ...mapActions(['gaiCount'])
  }
}
</script>

Module

所有数据都放在一起数据会乱

把数据模块化,把数据和方法按照彼此的关联关系进行封装

import Vue from "vue";
import Vuex from 'vuex'
import carModule from '@/store/cart.js'

Vue.use(Vuex);

export default new Vuex.Store({
    //开启严格模式
    strict: true,
    //注册vuex的模块
    modules: {
        //模块名
        cart: carModule
    }
});

cart.js

//购物车案例

export default {
 state(){
   return {
     list: []
   }
 },
 mutations: {
   show(){
     console.log('调用count里的show');
   }
 },
 actions: {},
 getters: {},
}

namespaced

  • 命名空间
  • 解决模块之间命名冲突问题
  • 加在模块里
export default({
    //开启命名空间
    namespaced: true,
});
<p>count 值:{{$store.state.cart.count}}</p>
<button class="btn btn-primary" @click="$store.commit('cart/show')">+1</button>

访问开启命名空间的数据

<!-- state -->
<p>count 值:{{$store.state.cart.count}}</p>
<!-- getters -->
<p>count 值:{{$store.getters['cart/pingfang']}}</p>
<!-- mutations -->
<button class="btn btn-primary" @click="$store.commit('cart/updateCount',3)">+1</button>
<!-- actions -->
<button class="btn btn-primary" @click="$store.dispatch('cart/xiugai',1)">+1</button>

模块简调用

import { mapState,mapMutations,mapGetters,mapActions } from 'vuex'

export default {
  name: 'Right',
  //计算属性
  computed:{
    ...mapState('cart',['count']),
    //如果属性冲突 使用对象赋值
    ...mapState('cart',{ cardCount: 'count' }),
    ...mapGetters('cart',['pingfang'])
  },
  //方法
  methods: {
    ...mapMutations('cart',['updateCount']),
    ...mapGetters('cart',['xiugai'])
  }
}

vue组件库

严格检查ESLint

不支持 函数后面加空格

修改eslintrc.js

 rules: {
   //在rules里添加  
   // 控制函数名和小括号之间,不需要空格
     'space-before-function-paren': [
       'error',
       {
         anonymous: 'always', // 普通的匿名函数,always表示需要空格;never表示不需要空格
         named: 'never', // 普通的命名函数
         asyncArrow: 'always' // 针对箭头函数
       }
     ]
 }

配置Axios

npm i axios

//requet/request.js
import axios from 'axios'

// 创建axios实例
const obj = axios.create({
  // 配置axios全局路径
  baseURL: 'http://www.liulongbin.top:3006'
})

export default obj

posted @ 2022-06-07 23:53  rain_sparse  阅读(45)  评论(0)    收藏  举报