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 @   rain_sparse  阅读(18)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示