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> |
| |
| const vm = new Vue({ |
| |
| el: "#app", |
| |
| data: { |
| username: 'giao', |
| gender: '女' |
| } |
| }) |
| </script> |
vue-指令
提升DOM的渲染效率 , 一套特殊的语法
内容渲染指令 {
| <div id="app"> |
| <p>{{username}}</p> |
| |
| |
| <p v-text="age">年龄:</p> |
| |
| <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"> |
| |
| <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', |
| |
| data: { |
| |
| }, |
| |
| methods: { |
| |
| fn1() { |
| console.log('移入'); |
| }, |
| fn2() { |
| console.log('移出'); |
| } |
| } |
| }); |
| </script> |
$event
| <div id="app"> |
| |
| <button @click="dianji1">不传参</button> |
| |
| |
| <button @click="dianji2(123)">传参</button> |
| |
| |
| <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); |
| |
| 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> |
| |
| |
| |
| <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"> |
| |
| <p v-if="flag">v-if使用</p> |
| |
| <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> |
| |
| <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.arr.push({id: this.nextId ,name: this.name}); |
| this.name = ''; |
| } |
| } |
| }); |
| </script> |
过滤器
| <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: { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| user: { |
| |
| handler(newVal) { |
| |
| console.log(newVal.name); |
| }, |
| |
| deep: true , |
| |
| immediate: true |
| } |
| } |
| |
| }); |
去掉温馨提示
| |
| Vue.config.productionTip = false; |
| |
| vm.$mount("#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() { |
| 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> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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: { |
| |
| |
| |
| 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 install -g @vue/cli |
| |
| vue create 项目名 |
vue组件化
把重用的ui组件化
- template
-
- 只能有一个根元素
- 其他元素只能是这个元素的子元素
- 不会被渲染成真正的dom元素
- script
-
- JavaScript
- 组件相关的data methods
- 写js 必须写 export default {}
- data须是函数 data(){}
- style
-
体验
| <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配置
注册组件
| |
| import Left from './components/Left.vue' |
| |
| 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"> |
| |
| |
| |
| <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: { |
| name: { |
| |
| default: 'user', |
| |
| |
| type: String , |
| |
| required: true |
| }, |
| newName: {}, |
| obj: {} |
| } |
| } |
| </script> |
子传父
父元素接收的数据与子元素互不影响
重新发送 重新接收
| |
| |
| <button @click="abc">传值</button> |
| <script> |
| export default { |
| data() { |
| return { |
| username: '张三', |
| obj: { |
| a: 1, |
| b: 2, |
| } |
| } |
| }, |
| methods: { |
| abc() { |
| |
| |
| 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 && true |
| true && true |
动态类名
| |
| <h1 :class="['类名1','类名2',flag ? '类名3 : ']"> |
| xxxxx |
| </h1> |
注册Vue的插件
| |
| let user = {name: 'giao',age:20} |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Vue.use((Vue) => { |
| Vue.prototype.lt = user; |
| }); |
| |
| |
| |
| console.log(this.lt.name) |
在项目中使用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]) |
| |
| |
| 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('color',{ |
| |
| |
| |
| bind(el,obj){ |
| el.style.color = obj.vule |
| }, |
| |
| update(el,obj){ |
| el.style.color = obj.vule |
| }, |
| }); |
| |
| |
| Vue.directive('color' ,(el,obj){ |
| el.style.color = obj.vule |
| },) |
| |
| |
URL与Hash
前端路由
- 访问不同的Hash 地址 会显示不同的组件
- SPA指单页面
- 不同组件切换都要依赖前端路由完成
路由工作原理
① 用户点击了页面上的路由链接
② 导致了 URL 地址栏中的 Hash 值发生了变化
③ 前端路由监听了到 Hash 地址的变化
④ 前端路由把当前 Hash 地址对应的组件渲染都浏览器中
简单实现路由
| data() { |
| return { |
| comName: 'Home' |
| } |
| }, |
| created() { |
| |
| window.onhashchange = () => { |
| console.log(location.hash); |
| let hash = location.hash; |
| this.comName = (hash == '#/home' ) ? 'Home' : |
| (hash == '#/movie') ? 'Movie' : |
| (hash == '#/about') ? 'About' : ''; |
| } |
| } |
| |
| |
| <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
| |
| import Vue from "vue"; |
| import VueRouter from 'vue-router'; |
| |
| |
| Vue.use(VueRouter) |
| |
| |
| const router = new VueRouter(); |
| |
| |
| export default router |
| 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) |
| |
| |
| const router = new VueRouter({ |
| routes: [ |
| |
| {path: '/home',component: Home}, |
| {path: '/movie',component: Movie}, |
| {path: '/about',component: About} |
| ] |
| }); |
重定向
| |
| {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> |
| |
| |
| 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: '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> |
| |
| 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> |
| |
| const router = new VueRouter({ |
| routes: [ |
| |
| {path: '/movie/:id/:name',component: Movie,props:true} |
| ] |
| }); |
vue-router 导航API
- this.$router.push('hash地址');
-
- this.$router.go('数值')
-
| methods: { |
| back() { |
| this.$router.go(-1); |
| } |
| } |
| methods: { |
| tiao(){ |
| this.$router.push('/about') |
| } |
| } |
全局前置守卫
| |
| router.beforeEach((to,from,next) => { |
| |
| |
| |
| |
| if(to.path == '/login'){ |
| next() |
| }else{ |
| |
| if (localStorage.getItem('token')) { |
| next() |
| } else { |
| next('/login'); |
| } |
| } |
| }) |
懒加载
| |
| |
| |
| |
| const router = new VueRouter({ |
| routes: [ |
| |
| |
| {path: '/login',component: () => import('@/components/MyLogin.vue')}, |
| ] |
| }); |
Vuex
vuex简介
- 实现大范围数据共享
- 能够方便,高效的数据共享
- 数据存取一步到位
- 数据流动非常清晰
- 数据驱动视图
安装
npm i vuex@3.6.2
Store创建
创建store/index.js
| |
| import Vue from "vue"; |
| |
| import Vuex from 'vuex' |
| |
| Vue.use(Vuex); |
| |
| const store = new Vuex.Store({}); |
| |
| export default store |
main.js
| |
| 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> |
展开运算符
store严格模式
| |
| const store = new Vuex.Store({ |
| |
| strict: true, |
| |
| state : { |
| count: 100, |
| name: '张三' |
| }, |
| }); |
Mutation
专门修改Store中的数据
只能写同步任务
| |
| const store = new Vuex.Store({ |
| |
| mutations: { |
| |
| |
| changeCount(state,n) { |
| state.count ++; |
| } |
| } |
| }); |
| |
| <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
写异步任务
| |
| const store = new Vuex.Store({ |
| mutations: { |
| |
| |
| |
| changeCount(state,n=1) { |
| state.count += n; |
| } |
| }, |
| |
| actions: { |
| gaiCount(ctx) { |
| setTimeout(() => { |
| |
| 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
计算属性
| |
| 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, |
| |
| 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: { |
| |
| |
| 'space-before-function-paren': [ |
| 'error', |
| { |
| anonymous: 'always', |
| named: 'never', |
| asyncArrow: 'always' |
| } |
| ] |
| } |
配置Axios
npm i axios
| |
| import axios from 'axios' |
| |
| |
| const obj = axios.create({ |
| |
| baseURL: 'http://www.liulongbin.top:3006' |
| }) |
| |
| export default obj |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步