VUE2从入门到精通(二)

118、ref引用
【1】JQuery里面的$("#app")。vue mv vm
【2】在vue中,程序员不需要操作dom。程序员只需要维护好数据即可(数据驱动视图)。所以在vue下,强烈不建议使用jquery!!!
【3】假设在vue项目中需要操作dom,怎么办呢,vue提供了ref,在不依赖jquery的情况下获取dom。
<!--第1部分-->
<template><div><h1 ref="ref_h1">App.vue父组件---{{countFromSon}}</h1> <!--!!!!!!!!!!!!!!!!!!!!!!--><button @click="showThis">打印this</button></div>
</template><!--第2部分-->
<script>// 导入需要使用的组件/* import Left from "@/components/Left";import Right from "@/components/Right";*/export default {/*  components: {Left,Right},*/data() {return {// 定义从子组件传值的属性countFromSon: 0}},methods: {showThis() {// console.log(this)this.$refs.ref_h1.style.color = "black" // !!!!!!!!!!!!!!!!!!!!!!!!!!}}}
</script><!--第3部分-->
<style>.box {background-color: pink;border: 3px solid black;h1 {color: red;}}
</style>

****************************************************************************************************************************************************************************

119、使用ref引用组件实例
【1】感觉这种方式也可以用于父子兄弟传值呀.... 卧槽!!!!!!!!这个方案最简单的呀,from老师的透露!!!!!!!!!
【2】Left.vue
<template><div>我是Left.vue子组件---{{count}}<br/><button @click="count=count+1">点击+1</button><button @click="count=0">重置</button></div>
</template><script>import eventBus from "@/components/eventBus";export default {name: "Left",data() {return {count: 0}},methods: {sendMsg() {// 通过eventBus发送数据eventBus.$emit("sendMsgToBrotherRight", this.msg)}}}
</script><style scoped>.box {background-color: yellow;}
</style>
【3】App.vue
<!--第1部分-->
<template><div><h1>App.vue父组件</h1><button @click="showThis">打印this</button><button @click="reset">重置Left组件的count</button><Left ref="refLeft"></Left></div>
</template><!--第2部分-->
<script>// 导入需要使用的组件import Left from "@/components/Left";import Right from "@/components/Right";export default {components: {Left,Right},data() {return {name: '陈翔'}},methods: {showThis() {console.log(this)},reset() {this.$refs.refLeft.count = 0}}}
</script><!--第3部分-->
<style>.box {background-color: pink;border: 3px solid black;h1 {color: red;}}
</style>

****************************************************************************************************************************************************************************

120、初步实现按钮与文本框依次展示
【1】实现切换
<!--第1部分-->
<template><div><h1>App.vue父组件</h1><hr/><input type="text" v-if="visFlag" @blur="showButton"/><button @click="showInput" v-else>展示输入框</button></div></template><!--第2部分-->
<script>// 导入需要使用的组件import Left from "@/components/Left";import Right from "@/components/Right";export default {components: {Left,Right},data() {return {// 控制输入框与按钮展示切换visFlag: false}},methods: {showThis() {console.log(this)},reset() {this.$refs.refLeft.count = 0},showInput() {this.visFlag = true},showButton() {this.visFlag = false}}}
</script><!--第3部分-->
<style>.box {background-color: pink;border: 3px solid black;h1 {color: red;}}
</style>
【2】解决input不自动获取焦点问题。updated不行因为当隐藏input的时候,refInput还是未定义,会报错。感觉也可以使用v-show,我真是个天才呀。
<!--第1部分-->
<template><div><h1>App.vue父组件</h1><hr/><input type="text" v-if="visFlag" @blur="showButton" ref="refInput"/><button @click="showInput" v-else>展示输入框</button></div></template><!--第2部分-->
<script>// 导入需要使用的组件import Left from "@/components/Left";import Right from "@/components/Right";export default {components: {Left,Right},data() {return {// 控制输入框与按钮展示切换visFlag: false}},methods: {showThis() {console.log(this)},reset() {this.$refs.refLeft.count = 0},showInput() {this.visFlag = true// Cannot read properties of undefined (reading 'focus')" 报错是因为还没有updated完毕/* console.log(this.$refs.refInput)this.$refs.refInput.focus()*/// 用到了延迟cb调用this.$nextTick(() => {  // 需要dom渲染完毕后 执行  就是延迟执行。this.$refs.refInput.focus() // !!!!!!!!!!!!!!!!!!})},showButton() {this.visFlag = false}}}
</script><!--第3部分-->
<style>.box {background-color: pink;border: 3px solid black;h1 {color: red;}}
</style>

****************************************************************************************************************************************************************************

123、购物车案例-some循环
【1】主要是解决forEach的全部循环问题
<!--第1部分-->
<template><div><h1>App.vue父组件</h1></div></template><!--第2部分-->
<script>// 导入需要使用的组件export default {name: "App",data() {return {// 控制输入框与按钮展示切换myArray: ['小红', '倪大红', '苏大强', '宝贝']}},created() {/* this.myArray.forEach((item, index) => {console.log('OK')  // 打印4次,说明性能浪费,一直执行,return没用 。一旦开始 无法在中间停止if (item == '小红') {console.log("找到的索引位置为:" + index)return}})*/this.myArray.some((item, index) => {console.log('OK')if (item == '小红') {console.log("找到的索引位置为:" + index)return true // 通过return true 可以终止循环 固定写法}})},methods: {}}
</script><!--第3部分-->
<style>.box {background-color: pink;border: 3px solid black;h1 {color: red;}}
</style>

****************************************************************************************************************************************************************************

124、every循环
【1】都是true就返回true,有一项是false则返回false
<!--第1部分-->
<template><div><h1>App.vue父组件</h1></div></template><!--第2部分-->
<script>// 导入需要使用的组件export default {name: "App",data() {return {// 控制输入框与按钮展示切换myArray: [{id: 1, name: '西瓜', state: true},{id: 2, name: '橙子', state: true},{id: 3, name: '操作', state: false}]}},created() {const res = this.myArray.every(item => item.state)console.log(res)},methods: {}}
</script><!--第3部分-->
<style>.box {background-color: pink;border: 3px solid black;h1 {color: red;}}
</style>

****************************************************************************************************************************************************************************

125、reduce方法的使用
【1】普通用法
<!--第1部分-->
<template><div><h1>App.vue父组件</h1></div></template><!--第2部分-->
<script>// 导入需要使用的组件export default {name: "App",data() {return {// 控制输入框与按钮展示切换myArray: [{id: 1, name: '西瓜', state: true, price: 10, count: 1},{id: 2, name: '橙子', state: true, price: 20, count: 2},{id: 3, name: '操作', state: false, price: 30, count: 3}]}},created() {let totalPrice = 0; // 总价this.myArray.filter(item => item.state).forEach(item => {totalPrice = totalPrice + item.price * item.count})console.log(totalPrice)},methods: {}}
</script><!--第3部分-->
<style>.box {background-color: pink;border: 3px solid black;h1 {color: red;}}
</style>
【2】高级用法created() {// let totalPrice = 0; // 总价const res = this.myArray.filter(item => item.state).reduce((totalPrice, item) => {return totalPrice = totalPrice + item.price * item.count}, 0)console.log(res)}

****************************************************************************************************************************************************************************

126、reduce的简化写法
【1】缩写版const res = this.myArray.filter(item => item.state).reduce((totalPrice, item) => totalPrice = totalPrice + item.price * item.count, 0)console.log(res)

****************************************************************************************************************************************************************************

127、购入车案例
【1】git ee网址可以下载优秀的项目,天下武功唯快不破。想让自己厉害,现在厉害的项目做起。

****************************************************************************************************************************************************************************

128、发起axios请求
【1】async function(){...await}
【2】在created调用initCartList方法created() {this.initCartList();console.log('========')}

****************************************************************************************************************************************************************************

129、请求回来的数据存到data里面去
【1】请求数据在页面要用的,必须转存到data中。
【2】此list数据就是转存到data里定义的list数据。

****************************************************************************************************************************************************************************

130、渲染Goods列表
【1】在App里面引用Goods,然后使用v-for="item in list"循环展示

****************************************************************************************************************************************************************************

131、为Goods组件封装属性
【1】:goodsName="item.goods_name",把App拿到的item属性,传递给Goods组件使用。
【2】思路:父组件向子组件传值。包括名称、图片、价格等属性

****************************************************************************************************************************************************************************

132、Goods组件封装
【1】状态的封装

****************************************************************************************************************************************************************************

133、分析封装props
【1】:goods="item"  ====> 这是面向对象的思想,厉害 厉害  厉害goods: {type: Object,default: {}}
【2】假如有个商品列表页面{id,title,price,image}、促销商品列表页面{id,title,x_price,x_image}。如果用面向对象的思想,在Goods.vue就不能做兼容处理了
【3】所以,还是需要分开接受属性,我的哥哥呀。还得是老师分开的对。解决了是用goods.price还是goods.x_price呢,所以还是得分开写。提升了复用性。

****************************************************************************************************************************************************************************

134、如何修改商品
【1】@change 只要复选框勾选状态发生变化,会自动触发change函数  @change="sonStateChange"/*勾选框状态改变触发的函数* 注意e 就是子组件通过$emit传递到父组件中的数据,格式为{id,value}*/sonStateChange(e) {const newState = e.target.checked; // 拿到最新状态this.$emit("son-fatherStateChange", {  // 以此名称为准id: this.id,value: newState,});},
【2】<Goods @son-fatherStateChange="fatherStateChange"></Goods>
fatherStateChange(e) {this.list.some((item) => {if (item.id === e.id) {item.goods_state = e.value;return true;}});},

****************************************************************************************************************************************************************************

136、修改对应商品的状态
【1】使用some即可fatherStateChange(e) {/*根据子组件传的id value修改list里面的数据*/this.list.some((item) => {if (item.id === e.id) {item.goods_state = e.value;return true;}});},

****************************************************************************************************************************************************************************

137、定义fullState
【1】使用every即可// 动态计算全选状态fullState() {return this.list.every((item) => item.goods_state);},
【2】自学能力、调试BUG能力、学习分析解决问题的能力。
【3】state是true还是false就决定是否全选了。
<!--底部组件  state就是全选的标记--><Footer:state="fullState"@isFull="getState":amount="totalAmount":totalPrice="totalPrice"></Footer>
【4】又是一轮子传父 Footer.vue---App.vue
<input type="checkbox" id="allCheck" :checked="state" @change="getState"/>
********************************************************************************************getState(e) {this.$emit('sonFatherIsFull', e.target.checked)}
********************************************************************************************/*全选按钮的切换*/getState(val) {this.list.forEach((item) => {item.goods_state = val;});},
【5】父传子---子传父

****************************************************************************************************************************************************************************

140、总数量、价格的计算
【1】App的computed计算属性里面/*已勾选商品的数量*/totalAmount() {return this.list.filter((item) => item.goods_state).reduce((amount, item) => (amount += item.goods_count), 0);},
***************************************************************先指令后函数绑定
<Footer:state="fullState":amount="totalAmount":totalPrice="totalPrice"@sonFatherIsFull="getState"></Footer>
【2】也是App的computed计算属性里面
【3】父传子---子再传子...

****************************************************************************************************************************************************************************

142、发送给App.vue
【1】发现一个问题Counter---Goods---App传两次太麻烦了...不如都在App.vue中引用,这样最多就是父子关系对吧。App.vue是所有的父,其他的都是子。<Goodsv-for="item in list":key="item.id":goodsName="item.goods_name":goodsPrice="item.goods_price":imgUrl="item.goods_img":goodsState="item.goods_state":id="item.id"@son-fatherStateChange="fatherStateChange"><!--商品的数量--><Counter:counter_goodsCount="item.goods_count"@amount-change="getNewAmount(item, $event)"></Counter></Goods>
*********************************************************************************/*最新商品数量*/getNewAmount(item, e) {console.log(e)item.goods_count = e;},
【2】学好Vue先给用组件名_变量名的形式规范定义变量。难度将会大大降低!!!!!!!!!!!!!!!!!!改完后看着舒服多了。
<template><div id="app"><Header></Header><!--循环渲染Goods--><Goodsv-for="item in list":key="item.id":Goods_goodsName="item.goods_name":Goods_goodsPrice="item.goods_price":Goods_imgUrl="item.goods_img":Goods_goodsState="item.goods_state":Goods_id="item.id"@Goods_sonFatherStateChange="Goods_sonFatherStateChange"><!--商品的数量--><Counter:Counter_goodsCount="item.goods_count"@amount-change="getNewAmount(item, $event)"></Counter></Goods><!--底部组件  state就是全选的标记--><Footer:Footer_state="fullState":Footer_amount="totalAmount":Footer_totalPrice="totalPrice"@Footer_sonFatherIsFull="Footer_sonFatherIsFull"></Footer></div>
</template><script>import Header from "@/components/Header";import Goods from "@/components/Goods";import Footer from "@/components/Footer";import axios from "axios";import Counter from "@/components/Counter";export default {name: "App",data() {return {list: [],};},components: {Header,Goods,Counter,Footer,},methods: {// 封装请求列表数据方法async initCartList() {// 结构data后重命名为resconst {data: res} = await axios.get("https://www.escook.cn/api/cart");if (res.status === 200) {this.list = res.list;console.log(res.list);}},Goods_sonFatherStateChange(e) {/*根据子组件传的id value修改list里面的数据*/this.list.some((item) => {if (item.id === e.id) {item.goods_state = e.value;return true;}});},/*全选按钮的切换*/Footer_sonFatherIsFull(val) {this.list.forEach((item) => {item.goods_state = val;});},/*最新商品数量*/getNewAmount(item, e) {console.log(JSON.stringify(item) + "============" + e)item.goods_count = e;},},created() {this.initCartList();console.log('========')},computed: {// 动态计算全选状态fullState() {return this.list.every((item) => item.goods_state);},/*已勾选商品的价格*/totalAmount() {return this.list.filter((item) => item.goods_state).reduce((amount, item) => (amount += item.goods_count), 0);},totalPrice() {return this.list.filter((item) => item.goods_state).reduce((totalPrice, item) =>(totalPrice += item.goods_count * item.goods_price),0);},},};
</script><style lang="less">
</style>

****************************************************************************************************************************************************************************

144、动态计算已勾选的商品
【1】越看越知道规范命名的重要性,一是规范命名,二是命名能起到区分的作用才最重要的。
【2】南朝四百八十寺,多少楼台烟雨中?

****************************************************************************************************************************************************************************

145、课程概述
【1】动态组件、插槽、自定义指令(没必要吧)

****************************************************************************************************************************************************************************

146、动态组件
【1】控制多个组件的隐藏与展示
【2】<component>组件,专门实现动态组件的渲染
【3】is属性的值就是渲染组件的名字。:is='comName' 动态绑定属性的值。
<template><div><h1>App根组件</h1><!--动态组件渲染--><component :is="comName"></component></div>
</template><script>import Left from "@/components/Left";import Right from "@/components/Right";export default {name: "App",data() {return {comName: 'Left'};},components: {Left,Right},methods: {}};
</script><style>
</style>

****************************************************************************************************************************************************************************

147、动态切换组件的展示
【1】动态修改属性的值而已
<template><div><h1>App根组件</h1><button @click="comName='Left'">展示 Left</button><button @click="comName='Right'">展示 Right</button><!--动态组件渲染--><component :is="comName"></component></div>
</template><script>import Left from "@/components/Left";import Right from "@/components/Right";export default {name: "App",data() {return {comName: 'Left'};},components: {Left,Right},methods: {}};
</script><style>
</style>

****************************************************************************************************************************************************************************

148、keep-alive的使用
【1】如果Left组件有个自增函数,但当切换Right后再切回Left会发现,left组件重新初始化了,值也变为了0。
<h3>Left组件---{{count}}</h3>
<button @click="count=count+1">点击+1</button>
*********************************************************************
<template><div><h3>Left组件---{{count}}</h3><button @click="count=count+1">点击+1</button></div>
</template><script>export default {name: "Left",data() {return {count: 0}},created() {console.log("Left创建")},destroyed() {console.log("Left销毁")}}
</script><style scoped>.box {background-color: yellow;}
</style>
【2】让离开时不被销毁,包一层<keep-alive>即可。可以把内部的组件进行缓存,而不是销毁。<!--动态组件渲染--><keep-alive><component :is="comName"></component></keep-alive>

****************************************************************************************************************************************************************************

149、keep-alive组件指定
【1】include属性,通过include="Left,Another"只会缓存Left与Another,多个用逗号间隔。<!--动态组件渲染--><keep-alive include="Left,Another"><component :is="comName"></component></keep-alive>
【2】exclude代表排除组件。但是不能与include同时使用。

****************************************************************************************************************************************************************************

150、组件注册名称
【1】如果在声明组件时,没有为组件指定name名称,则组件名称默认就是注册时名称。
【2】默认的都是使用默认与组件名一样的名称。

****************************************************************************************************************************************************************************

151、插槽
【1】是vue为组件封装者提供的能力,一般开发用不到。
【2】<slot></slot>占位标签。小霸王游戏机的插槽来插卡,插什么样的卡,就是什么样的游戏
<template><div><h3>Left组件---{{count}}</h3><!--声明一个插槽--><slot></slot></div>
</template><script>export default {name: "Left",data() {return {count: 0}},created() {console.log("Left创建")},destroyed() {console.log("Left销毁")}}
</script><style scoped>.box {background-color: yellow;}
</style>
***********************************************************
<template><div><h1>App根组件</h1><Left>这是用来填充Left插槽的...</Left></div>
</template><script>import Left from "@/components/Left";import Right from "@/components/Right";export default {name: "App",data() {return {comName: 'Left'};},components: {Left,Right},methods: {}};
</script><style>
</style>

****************************************************************************************************************************************************************************

152、v-slot指令
【1】<slot></slot>默认的name="default"
<slot name="default"></slot>
【2】指定插槽的名称,放置内容。template只起到包裹作用,不是真正的标签。<Left><template v-slot:default> // !!!!!!!!!!!!!!<span>这是用来填充Left插槽的...</span></template></Left>
【3】 v-slot:default必须用在template标签上,不能用在普通元素标签上。

****************************************************************************************************************************************************************************

153、v-slot的简写形式
【1】v-slot:简写是#
【2】插槽的默认内容指定
<template><div class="box"><h3>Left组件---{{count}}</h3><!--声明一个插槽--><slot name="default">这是名字为default的slot ...默认的</slot></div>
</template>

****************************************************************************************************************************************************************************

154、具名插槽的定义与使用
【1】Vant组件库。插槽的一一定义,与对应的一一使用。
<template><div><!--标题--><div><slot name="title"></slot></div><!--内容--><div><slot name="content"></slot></div><!--作者--><div><slot name="author"></slot></div></div>
</template><script>export default {name: "Article"}
</script><style scoped>.article-container {> div {min-height: 150px;}.header-box {background-color: pink;}.content-box {background-color: lightblue;}.footer-box {background-color: lightcoral;}}
</style>
【2】使用时一一对应
<template><div><h1>App根组件</h1><Article><template #title><span>一首诗</span></template><template #content><span>琴瑟无端五十铉,一年一柱思华年</span></template><template #author><span>李商隐</span></template></Article></div>
</template><script>import Left from "@/components/Left";import Right from "@/components/Right";import Article from "@/components/Article";export default {name: "App",data() {return {comName: 'Left'};},components: {Left,Right,Article},methods: {}};
</script><style>
</style>

****************************************************************************************************************************************************************************

155、作用域插槽的基本用法
【1】插槽里定义数据。加了属性的插槽就变成了作用域插槽。<!--内容--><div class="content-box"><slot name="content" msg="Hello Vue"></slot></div>
【2】父组件接收使用的是{}对象,.属性就可以使用了。<template #content="object"><span>琴瑟无端五十铉,一年一柱思华年</span>{{object.msg}}
</template>

****************************************************************************************************************************************************************************

156、作用域插槽解构赋值
【1】作用域插槽
<template><div><!--标题--><div><slot name="title"></slot></div><!--内容--><div><slot name="content" msg="Hello Vue" :user="user"></slot></div><!--作者--><div><slot name="author"></slot></div></div>
</template><script>export default {name: "Article",data() {return {user: {name: "陈翔",age: 20}};},}
</script><style scoped>.article-container {> div {min-height: 150px;}.header-box {background-color: pink;}.content-box {background-color: lightblue;}.footer-box {background-color: lightcoral;}}
</style>
【2】解构msg<template #content="{msg}"><span>琴瑟无端五十铉,一年一柱思华年</span><br/>{{msg}}
</template>
【3】解构user<template #content="{user}"><span>琴瑟无端五十铉,一年一柱思华年</span><br/>{{user}}
</template>
【4】同时结构
<template #content="{msg,user}"><span>琴瑟无端五十铉,一年一柱思华年</span><br/>{{msg}} {{user}}
</template>

****************************************************************************************************************************************************************************

157、基于slot插槽购物车重构
【1】功能一定好好测试,确实容易漏问题,人非圣贤,孰能无过。定义插槽<div class="goods_pa"><div class="price">¥{{ Goods_goodsPrice }}</div><slot></slot></div>
【2】使用插槽。<Counter:Counter_goodsCount="item.goods_count"@amount-change="getNewAmount(item, $event)">
</Counter>

****************************************************************************************************************************************************************************

160、私有自定义指令
【1】定义名字为color的指令,指向一个配置对象<h1 v-color>App根组件</h1>*************************************directives: {color: {}},
*******************************************<h1>哪个元素绑定,哪个元素变红!!!
<template><div><h1 v-color>App根组件</h1><Article><template #title><span>一首诗</span></template><template #content="{msg,user}"><span>琴瑟无端五十铉,一年一柱思华年</span><br/>{{msg}} {{user}}</template><template #author><span>李商隐</span></template></Article></div>
</template><script>import Left from "@/components/Left";import Right from "@/components/Right";import Article from "@/components/Article";export default {name: "App",components: {Left,Right,Article},directives: {color: {/*当指令第一次被绑定到元素上的时候,会立即触发bind函数*/bind(el) {console.log("触发v-color的bind函数...")el.style.color = "red"}}},methods: {}};
</script><style>
</style>

****************************************************************************************************************************************************************************

161、使用binding.value的值
【1】动态绑定data属性值。
<h1 v-color="color">App根组件</h1>
**************************************************data() {return {color: 'green'}},directives: {color: {/*当指令第一次被绑定到元素上的时候,会立即触发bind函数*/bind(el, binding) {console.log("触发v-color的bind函数..." + JSON.stringify(binding))el.style.color = binding.value}}},
***********************************************************这种传字符串的用法也可以
<h2 v-color="'black'">App根组件</h2>

****************************************************************************************************************************************************************************

162、自定义指令-update函数
【1】bind函数只会调用一次。更新则不会被执行
【2】 <button @click="color='red'">改变 color 的颜色值</button>data() {return {color: 'green'}},directives: {color: {/*当指令第一次被绑定到元素上的时候,会立即触发bind函数*/bind(el, binding) {console.log("触发v-color的bind函数..." + JSON.stringify(binding))el.style.color = binding.value},/*定义update!!!!!!!!!!!!!!*/update(el, binding) {console.log("触发v-color的bind函数..." + JSON.stringify(binding))el.style.color = binding.value}}},

****************************************************************************************************************************************************************************

163、自定义指令的简写
【1】原来的 VS 简写
color: {/!*当指令第一次被绑定到元素上的时候,会立即触发bind函数*!/bind(el, binding) {console.log("触发v-color的bind函数..." + JSON.stringify(binding))el.style.color = binding.value},/!*定义update*!/update(el, binding) {console.log("触发v-color的bind函数..." + JSON.stringify(binding))el.style.color = binding.value}}
****************************************************************************color(el, binding) {el.style.color = binding.value}

****************************************************************************************************************************************************************************

164、全局自定义指令
【1】像定义全局过滤器一样。这样不管是App.vue还是Article.vue都能用了。
/*main.js*/
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'Vue.config.productionTip = false
// 全局自定义指令
Vue.directive('color', function (el, binding) {el.style.color = binding.value
})new Vue({render: h => h(App),
}).$mount('#app')

****************************************************************************************************************************************************************************

165、main.js的小提示
【1】Vue.config.productionTip = false /*控制台console能不能看到提示,没有什么实际意义*/

****************************************************************************************************************************************************************************

166、eslint概述与作用
【1】约定代码风格。结尾要不要分号、缩进几个空格,保证写出代码的风格几乎是完全一样的。一开始用会比较难。
【2】WebStorm设置File---Settings---Editor-code style --- javascript
【3】no-console... no-debugger
【4】常用的eslint的语法,名字后面少一个空格。/**/前后强制使用一样的间距。
【5】vscode配置eslint

****************************************************************************************************************************************************************************

172、axios 的基本用法
【1】npm i axios -S
<template><div><h3>Left组件---</h3><button @click="getInfo">发起GET请求</button></div>
</template><script>import axios from 'axios'export default {name: "Left",data() {return {count: 0}},methods: {async getInfo() {const {data} = await axios.get(`http://localhost:8002/login`);console.log(data)}}}
</script><style scoped>.left-container {background-color: orange;min-height: 200px;flex: 1;}
</style>
【2】发起post请求
<template><div><h3>Right组件</h3><button @click="postInfo">发起POST请求</button></div>
</template><script>import axios from 'axios'export default {name: "Right",methods: {async postInfo() {const {data} = await axios.post(`http://localhost:8002/login`)console.log(data)}}}
</script><style scoped>.right-container {background-color: lightblue;min-height: 200px;flex: 1;}
</style>

****************************************************************************************************************************************************************************

173、把axios挂载到vue
【1】挂载到Vue原型属性
/*main.js*/
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'Vue.config.productionTip = false /*控制台console能不能看到提示,没有什么实际意义*/
// 全局自定义指令
Vue.directive('color', function (el, binding) {el.style.color = binding.value
})
// 挂载axios
Vue.prototype.axios = axiosnew Vue({render: h => h(App),
}).$mount('#app')
【2】const {data} = await this.axios.get(`http://localhost:8002/login`);使用不需要import操作了。
【3】后端路径优化操作!!!!!!!!!!!!!!!还是挂原型。这个比青戈讲的透彻呀。
// 挂载axios
axios.defaults.baseURL = `http://localhost:8002`   // !!!!!!!!!!!!!
Vue.prototype.axios = axios

****************************************************************************************************************************************************************************

174、axios不利于API接口的复用。
【1】它无法实现API接口的复用。每次调用都需要重新写请求方法与请求参数。
【2】所以还有优化的空间。

****************************************************************************************************************************************************************************

175、路由的概念
【1】英文router,就是对应关系。SPA单页面应用程序。
【2】前端里,路由就是Hash地址,就是页面与地址的对应关系。

****************************************************************************************************************************************************************************

176、路由的工作方式
【1】点击路由链接---导致URL地址栏中Hash值发生变化---前端路由监听变化---Hash地址对应组件渲染到浏览器中。

****************************************************************************************************************************************************************************

178、路由的基本用法
【1】vue-router路由包,只能在vue项目使用。注意看官方文档。
【2】使用
*********************************************安装vue-router包
npm i vue-router@3.5.2 -S
*********************************************创建路由模块.js文件
src/router/index.js
*********************************************导入挂载
/*index.js路由模块*/
// 导入
import Vue from "vue";
import VueRouter from "vue-router";
// 调用
Vue.use(VueRouter)
// 创建路由实例对象
const router = new VueRouter()
// 向外共享路由实例对象
export default router
*********************************************声明路由和占位符
/*main.js*/
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'
import myRouter from './router/index.js'  // 导入路由模块,拿到路由的实例对象Vue.config.productionTip = false /*控制台console能不能看到提示,没有什么实际意义*/
// 全局自定义指令
Vue.directive('color', function (el, binding) {el.style.color = binding.value
})
// 挂载axios
axios.defaults.baseURL = `http://localhost:8002`
Vue.prototype.axios = axiosnew Vue({render: h => h(App),router: myRouter
}).$mount('#app')

****************************************************************************************************************************************************************************

179、基本用法-注意点
【1】import myRouter from './router/index.js'  可以写成import myRouter from './router'
【2】说明,如果给定的是文件夹,则默认是文件夹下面的index.js文件

****************************************************************************************************************************************************************************

180、路由模块基本用法、
【1】App中使用
<template><div><h1>App组件</h1><hr/><a href="#/home">首页</a><a href="#/movie">电影</a><a href="#/about">关于</a><hr/><!--只要在main.js配置了vue-router,则·可以使用router-view--><router-view></router-view></div>
</template><script>export default {name: "App",};
</script><style scoped>.box {display: flex;}
</style>
【2】index.js定义Hash与页面的对应关系
/*路由模块*/
// 导入
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "@/components/Home";
import Move from "@/components/Movie";
import About from "@/components/About";// 调用
Vue.use(VueRouter)// 创建路由实例对象
const router = new VueRouter({// routers是一个数组,是来定义hash地址与组件间的对应关系的。routes: [ // !!!!!!!!!!!!!注意不是routers{path: '/home', component: Home},{path: '/movie', component: Move},{path: '/about', component: About},]
})// 向外共享路由实例对象
export default router

****************************************************************************************************************************************************************************

181、路由基本用法
【1】下面的就是叫做“路由规则”routes: [{path: '/home', component: Home},{path: '/movie', component: Move},{path: '/about', component: About},]
【2】router-link就是用来替换a标签的
<!-- <a href="#/home">首页</a><a href="#/movie">电影</a><a href="#/about">关于</a>--><!--安装与配置了vue-router后可以用router-link来替换普通的链接了--><router-link to="/home">首页</router-link><router-link to="/movie">电影</router-link><router-link to="/about">关于</router-link>
【3】路由的重定向。解决访问localhost:8080能直接访问home页面,而不是空页面routes: [{path: '/', redirect: '/home'},/*重定向到home*/{path: '/home', component: Home},{path: '/movie', component: Move},{path: '/about', component: About},]

****************************************************************************************************************************************************************************

183、嵌套路由
【1】套娃{path: '/about',component: About,children: [{path: '/left', component: Left},{path: '/right', component: Right},]},
**********************************************************
<template><div class="about-container"><h3>About组件</h3><hr/><router-link to="/left">Left组件</router-link><router-link to="/right">Right组件</router-link><hr/><router-view></router-view></div>
</template>

****************************************************************************************************************************************************************************

185、嵌套路由-默认子路由
【1】子路由一般不写/
<router-link to="/about/left">Left组件</router-link>
<router-link to="/about/right">Right组件</router-link>
【2】子路由一般不写/{path: '/about',component: About,redirect: '/about/left', // 默认子路由页面children: [//需要注意的是:子路由规则不要以/开头{path: 'left', component: Left},{path: 'right', component: Right}]}
【3】完整路由
/*路由模块*/
// 导入
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "@/components/Home";
import Move from "@/components/Movie";
import About from "@/components/About";
import Left from "@/components/Left";
import Right from "@/components/Right";// 调用
Vue.use(VueRouter)// 创建路由实例对象
const router = new VueRouter({// routers是一个数组,是来定义hash地址与组件间的对应关系的。routes: [{path: '/', redirect: '/home'},/*重定向到home*/{path: '/home', component: Home},{path: '/movie', component: Move},{path: '/about',component: About,redirect: '/about/left',children: [//需要注意的是:子路由规则不要以/开头{path: 'left', component: Left},{path: 'right', component: Right}]},]
})// 向外共享路由实例对象
export default router

****************************************************************************************************************************************************************************

186、动态路由匹配
【1】/mv/1  /mv/2  /mv/3不同的短片mv,怎么定向?
【2】使用英文的冒号: 可以指定动态路由项目。{path: '/movie/:id', component: Move},
【3】这样电影1-5都能匹配到Move组件。
<router-link to="/home">首页</router-link>
<router-link to="/movie/1">电影1</router-link>
<router-link to="/movie/2">电影2</router-link>
<router-link to="/movie/3">电影3</router-link>
<router-link to="/movie/4">电影4</router-link>
<router-link to="/movie/5">电影5</router-link>
【4】需求,Move组件中需要根据id的值来展示对应电影的详情信息。还可以写成 <span>获取到的id的值为{{$route.params.id}}</span>
<template><div class="movie-container"><h3>Movie组件</h3><!--<button @click="printThis">打印</button>--><span>获取到的id的值为{{this.$route.params.id}}</span>  !!!!!!!!!!!!!!!!!</div>
</template><script>export default {name: "Move"}
</script><style scoped></style>

****************************************************************************************************************************************************************************

187、动态路由-开启props
【1】this.$route是路由的参数对象。this.$router是路由的导航对象。
***************************************开启propsroutes: [{path: '/', redirect: '/home'},/*重定向到home*/{path: '/home', component: Home},{path: '/movie/:id', component: Move, props: true}, // !!!!!!必须开启{path: '/about',component: About,redirect: '/about/left',children: [//需要注意的是:子路由规则不要以/开头{path: 'left', component: Left},{path: 'right', component: Right}]},]
***************************************接收export default {name: "Move",props: ['id']}
***************************************使用
<span>获取到的id的值为{{this.$route.params.id}}---{{id}}</span>
【2】props: true路由规则里有参数项,必须指定。如果没有参数的就无需指定了。

****************************************************************************************************************************************************************************

188、拓展query和fullPath
【1】/movie/2  斜线后面2这叫做路径参数。
*************************************************
$route.params.id通过这个来拿$route.params.xxx
【2】/movie/2?name=zs&age=20 这种叫做查询参数
*************************************************
问号后面的参数项,叫做查询参数
通过this.$route.query查询
*************************************************可以通过Movie.vue打印this查看
<template><div class="movie-container"><h3>Movie组件</h3><!--<button @click="printThis">打印</button>--><!--this.$route是路由的参数对象--><span>获取到的id的值为{{this.$route.params.id}}---{{id}}</span><button @click="showThis">打印this</button></div>
</template><script>export default {name: "Move",props: ['id'],methods: {showThis() {console.log(this);}}}
</script><style scoped></style>
【2】通过打印this可以看到path为/movie/2。而fullPath为/movie/2?name=zs。

****************************************************************************************************************************************************************************

189、编程式导航跳转-push、replace、go
【1】声明式导航(点击标签的形式)&编程式导航(js写代码实现的跳转)
【2】vue-router提供了编程式导航push、replace、go
*********************************都是this.$router(注意多个r)push 会增加一条历史记录
<template><div class="home-container"><h3>Home组件</h3><hr/><button @click="gotoMovie1">跳转到电影1页面</button></div>
</template><script>export default {name: "Home",methods: {gotoMovie1() {this.$router.push('/movie/1')}}}
</script><style scoped></style>
*********************************replace,跳转指定hash地址,并替换掉当前的历史记录
<template><div class="home-container"><h3>Home组件</h3><hr/><button @click="pushMovie1">push跳转到电影1页面</button><button @click="replaceMovie1">replace跳转到电影1页面</button></div>
</template><script>export default {name: "Home",methods: {pushMovie1() {this.$router.push('/movie/1')},replaceMovie1() {this.$router.replace('/movie/1')}}}
</script><style scoped></style>
******************************************************************go(数值n)
<template><div class="movie-container"><h3>Movie组件</h3><!--<button @click="printThis">打印</button>--><!--this.$route是路由的参数对象--><span>获取到的id的值为{{this.$route.params.id}}---{{id}}</span><button @click="showThis">打印this</button><button @click="goBack">回退</button></div>
</template><script>export default {name: "Move",props: ['id'],methods: {showThis() {console.log(this);},goBack() {this.$router.go(-1)}}}
</script><style scoped></style>
******************************************************************go的简洁用法
this.$router.back()
this.$router.forward()

****************************************************************************************************************************************************************************

190、导航守卫可以控制路由的访问权限
【1】比如需要token才能访问
Main—>导航守卫(检测是否登录)—>Login登录—>Main后台主页
【2】全局前置守卫
******************************************************************
每次发生路由的导航跳转时,都会触发全局前置守卫。因此全局前置守卫中,程序
员可以对每个路由进行访问权限控制。
【3】守卫方法的3个形参to、from、next
******************************************************************router-index.js
// 为router声明全局前置导航守卫
// 发生路由跳转,必然触发beforeEach指定的function回调
router.beforeEach(function (to, from, next) {// next() 不调用则所有的路由都被拦截,不调谁都不能访问
})
******************************************************************
// 为router声明全局前置导航守卫
// 发生路由跳转,必然触发beforeEach指定的function回调
router.beforeEach(function (to, from, next) {console.log(from) // 将要离开的console.log(to) // 将要访问的next()
})

****************************************************************************************************************************************************************************

191、导航守卫-next函数的三种调用方式
【1】如果有访问权限,next() 直接放行
【2】如果没有访问权限,强制用next('/Login')强制访问Login页面
【3】强制停留在当前页面next(false)

****************************************************************************************************************************************************************************

192、路由守卫-控制访问权限
【1】定义Login和Main的路由规则
*********************************************************************
// 创建路由实例对象
const router = new VueRouter({// routers是一个数组,是来定义hash地址与组件间的对应关系的。routes: [{path: '/', redirect: '/home'},/*重定向到home*/{path: '/home', component: Home},{path: '/movie/:id', component: Move, props: true},{path: '/about',component: About,redirect: '/about/left',children: [//需要注意的是:子路由规则不要以/开头{path: 'left', component: Left},{path: 'right', component: Right}]},{path: "/login", component: Login},{path: "/main", component: Main},]
})
*********************************************************************拦截判断
router.beforeEach(function (to, from, next) {// 拿到用户将要访问的hash地址,如果等于/main 证明页面是需要登录才能访问的if (to.path === '/main') {const token = localStorage.getItem('token')if (token) {next()} else {next('/login')}} else {next()}
})
*********************************************************************模拟登录
在LocalStorage下面的本地网址添加token 123然后再点击登录

****************************************************************************************************************************************************************************

193、VUE2.0实例-安装和配置路由
【1】npm i vue-router@3.5.2 -S
**********************************************************路由的配置
Vue.use(VueRouter);
**********************************************************
import Vue from 'vue'
import App from './App.vue'
import router from './router'// 导入样式
import './assets/css/bootstrap.css'
import './index.css'Vue.config.productionTip = falsenew Vue({render: h => h(App),router
}).$mount('#app')

****************************************************************************************************************************************************************************

194、基于路由渲染登录组件
【1】在router-index.js里配置路由跳转
********************************************************************//登录的路由规则,上面导入{path: "/login",component: Login,},
********************************************************************App.vue
<template><!-- 路由占位符 --><router-view></router-view>
</template>
********************************************************************根路径重定向{path: "/",redirect: "/login",},

****************************************************************************************************************************************************************************

195、模拟登录
【1】登录的判断逻辑admin 123456
<template><div><div><!-- 头像区域 --><div class="text-center avatar-box"><img src="../assets/logo.png" class="img-thumbnail avatar" alt=""/></div><!-- 表单区域 --><div class="form-login p-4"><!-- 登录名称 --><div class="form-group form-inline"><label for="username">登录名称</label><input type="text" class="form-control ml-2" id="username" placeholder="请输入登录名称" autocomplete="off"v-model.trim="username"/></div><!-- 登录密码 --><div class="form-group form-inline"><label for="password">登录密码</label><input type="password" class="form-control ml-2" id="password" placeholder="请输入登录密码"v-model.trim="password"/></div><!-- 登录和重置按钮 --><div class="form-group form-inline d-flex justify-content-end"><button type="button" class="btn btn-secondary mr-2" @click="reset">重置</button><button type="button" class="btn btn-primary" @click="login">登录</button></div></div></div></div>
</template><script>export default {name: 'MyLogin',data() {return {username: '',password: ''}},methods: {reset() { //!!!!!!!!!!!!!this.username = ''this.password = ''},login() { //!!!!!!!!!!!!!if (this.username === 'admin' && this.password === '123456') {//存储tokenlocalStorage.setItem('token', 'kong xxx')//跳转 到后台主页this.$router.push('/home')} else {//登录失败localStorage.removeItem('token')}}}}
</script><style scoped>.login-container {background-color: #35495e;height: 100%;.login-box {width: 400px;height: 250px;background-color: #fff;border-radius: 3px;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);.form-login {position: absolute;bottom: 0;left: 0;width: 100%;box-sizing: border-box;}}}.form-control {flex: 1;}.avatar-box {position: absolute;width: 100%;top: -65px;left: 0;.avatar {width: 120px;height: 120px;border-radius: 50% !important;box-shadow: 0 0 6px #efefef;}}
</style>

****************************************************************************************************************************************************************************

196、说明Token
【1】前缀带不带取决于后端服务器

****************************************************************************************************************************************************************************

197、实现后台主页的基础布局
【1】Home.vue
**************************************************************
<template><div><!-- 头部区域 --><MyHeader></MyHeader><!-- 页面主体区域 --><div><!-- 左侧边栏 --><MyAside></MyAside><!-- 右侧内容主体区 --><div><!-- 路由占位符 --><router-view></router-view></div></div></div>
</template>
【2】Header.vue
<template><div class="layout-header-container d-flex justify-content-between align-items-center p-3"><!-- 左侧 logo 和 标题区域 --><div class="layout-header-left d-flex align-items-center user-select-none"><!-- logo --><img src="../../assets/heima.png" alt=""><!-- 标题 --><h4 class="layout-header-left-title ml-3">黑马后台管理系统</h4></div><!-- 右侧按钮区域 --><div><button type="button" class="btn btn-light" @click="logout">退出登录</button></div></div>
</template><script>export default {name: 'MyHeader',methods: {logout() {//清空tokenlocalStorage.removeItem('token')//跳转回登录页面this.$router.push('/login')}}}
</script><style scoped>.layout-header-container {height: 60px;border-bottom: 1px solid #eaeaea;}.layout-header-left-img {height: 50px;}
</style>
【3】Aside.vue
<template><div><!-- 左侧边栏列表 --><ul class="user-select-none menu"><li><!-- 子路由链接要以/开头 --><router-link to="/home/users">用户管理</router-link></li><li><router-link to="/home/rights">权限管理</router-link></li><li><router-link to="/home/goods">商品管理</router-link></li><li><router-link to="/home/orders">订单管理</router-link></li><li><router-link to="/home/settings">系统设置</router-link></li></ul></div>
</template><script>export default {name: 'MyAside'}
</script><style scoped>.layout-aside-container {width: 250px;height: 100%;border-right: 1px solid #eaeaea;}.menu {list-style-type: none;padding: 0;.menu-item {line-height: 50px;font-weight: bold;font-size: 14px;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;&:hover {background-color: #efefef;cursor: pointer;}a {display: block;color: black;padding-left: 30px;&:hover {text-decoration: none;}}}}// 设置路由高亮效果.router-link-active {background-color: #efefef;box-sizing: border-box;position: relative;// 伪元素实现路由高亮效果&::before {content: ' ';display: block;width: 4px;height: 100%;position: absolute;left: 0;top: 0;background-color: #42b983;}}
</style>

****************************************************************************************************************************************************************************

199、实现子路由的嵌套展示
【1】具体的路由嵌套。
routes: [{path: "/",redirect: "/login",},//登录的路由规则,上面导入{path: "/login",component: Login,},//后台主页的路由规则{path: "/Home",component: Home,redirect: '/home/users',children: [//在router-link中需要写全/,在子路由规则中,子路由 / 不需要再写{path: 'users', component: Users},{path: 'rights', component: Rights},{path: 'goods', component: Goods},{path: 'orders', component: Orders},{path: 'settings', component: Settings},//用户详情页的路由规则 (只有在路由规则中可以出现冒号:){path: 'userinfo/:id', component: UserDetail},//第2+1种方式:users{path:'users/:id',component:UserDetail},// 在userdetail中获取路径中的id值信息(第二种方式)//{path:'userinfo/:id',component:UserDetail,props:true},]

****************************************************************************************************************************************************************************

200、点击进入用户详情页
【1】用户列表页面
<template><div><!-- 标题 --><h4>用户管理</h4><!-- 用户列表 --><table class="table table-bordered table-striped table-hover"><thead><tr><th>#</th><th>姓名</th><th>年龄</th><th>头衔</th><th>操作</th></tr></thead><tbody><tr v-for="item in userlist" :key="item.id"><td>{{item.id}}</td><td>{{item.name}}</td><td>{{item.age}}</td><td>{{item.position}}</td><td><a href="#" @click.prevent="gotoDeatail(item.id)">详情</a><!-- 第2+1种方式 --><!-- <router-link :to="'/home/users/' + item.id">详情</router-link> --></td></tr></tbody></table></div>
</template><script>export default {name: 'MyUser',data() {return {// 用户列表数据userlist: [{id: 1, name: '嬴政', age: 18, position: '始皇帝'},{id: 2, name: '李斯', age: 35, position: '丞相'},{id: 3, name: '吕不韦', age: 50, position: '商人'},{id: 4, name: '赵姬', age: 48, position: '王太后'}]}},methods: {gotoDeatail(id) {this.$router.push('/home/userinfo/' + id)}}}
</script><style scoped></style>
【2】用户详情页面
<template><div><button type="button" class="btn btn-light btn-sm" @click="$router.back()">后退</button><!-- 使用this.$route.params.id 获取路径中的id值信息(第一种方式)--><h4>用户详情 --- {{this.$route.params.id}}</h4><!-- (第二种方式)使用下面props属性赋值,并在路由规则中props:true,就可以直接使用id --><!-- <h4>用户详情 --- {{id}}</h4> --></div>
</template><script>export default {name: 'MyUserDetail',props: ['id']}
</script><style scoped></style>

****************************************************************************************************************************************************************************

201、升级用户详情页的路由
【1】动态写id传递id参数gotoDetail(id) {this.$router.push('/home/userinfo/' + id)
}
【2】详情页拿到id{{this.$route.params.id}}

****************************************************************************************************************************************************************************

202、路由path的注意点
【1】路由重定向{path: "/Home",component: Home,redirect: '/home/users',children: [//在router-link中需要写全/,在子路由规则中,子路由 / 不需要再写{path: 'users', component: Users},{path: 'rights', component: Rights},{path: 'goods', component: Goods},{path: 'orders', component: Orders},{path: 'settings', component: Settings},//用户详情页的路由规则 (只有在路由规则中可以出现冒号:){path: 'userinfo/:id', component: UserDetail},//第2+1种方式:users{path:'users/:id',component:UserDetail},// 在userdetail中获取路径中的id值信息(第二种方式)//{path:'userinfo/:id',component:UserDetail,props:true},]},【2】path后面不要跟大写字母,这是约定

****************************************************************************************************************************************************************************

203、如何控制页面的权限
【1】判断不需要权限的菜单集合
const pathArray=['/home','/home/users'];
if(pathArray.indexOf(to.path)!==-1){走token判断
}else{不走token判断
}

****************************************************************************************************************************************************************************

204、黑白头条项目结构
【1】vue-router的版本很重要
npm i vue-router@3.5.2 -S
******************************************************************
import Vue from 'vue'
import VueRouter from 'vue-router'// 1、把VueRouter安装为Vue的插件
Vue.use(VueRouter)// 2、路由规则数组
const routeArray = []// 3、创建路由实例对象
const router = new VueRouter({routes: routeArray
})//  4、导出路由实例对象
export default router
******************************************************************
import Vue from 'vue'
import App from './App.vue'
import router from "@/router"Vue.config.productionTip = falsenew Vue({router,render: h => h(App),
}).$mount('#app')
【2】说明从0敲才能学得会

****************************************************************************************************************************************************************************

205、安装配置Vant组件库
【1】现成的组件库
npm i vant@latest-v2
*********************************************************************
import Vue from 'vue'
import App from './App.vue'
import router from "@/router"
// 导入并安装vant插件
import Vant from 'vant'
import 'vant/lib/index.css'Vue.use(Vant)Vue.config.productionTip = falsenew Vue({router,render: h => h(App),
}).$mount('#app')
*********************************************************************<van-button type="primary">主要按钮</van-button><van-button type="success">成功按钮</van-button><van-button type="default">默认按钮</van-button><van-button type="warning">警告按钮</van-button><van-button type="danger">危险按钮</van-button>

****************************************************************************************************************************************************************************

206、初始化-使用Tabbar组件
【1】开启路由模式的tabBar
<template><div id="app"><!--路由占位符--><!--tabBar--><van-tabbar route><van-tabbar-item replace to="/" icon="home-o">首页</van-tabbar-item><van-tabbar-item replace to="/user" icon="user-0">我的</van-tabbar-item></van-tabbar></div>
</template><script>export default {name: "App"}
</script><style scoped>
</style>

****************************************************************************************************************************************************************************

207、通过路由展示对应页面
【1】你只管努力,生活会给你惊喜!!!!!!!!!!
<template><div id="app"><!--路由占位符--><router-view></router-view><!--tabBar--><van-tabbar route><van-tabbar-item icon="home-o" to="/">首页</van-tabbar-item><van-tabbar-item icon="user-o" to="/user">我的</van-tabbar-item></van-tabbar></div>
</template><script>export default {name: "App"}
</script><style scoped>
</style>
************************************************************************************
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "@/views/Home/Home";
import User from "@/views/User/User";// 1、把VueRouter安装为Vue的插件
Vue.use(VueRouter)// 2、路由规则数组
const routeArray = [// 首页路由规则{path: '/', component: Home},{path: '/user', component: User}
]// 3、创建路由实例对象
const router = new VueRouter({routes: routeArray
})//  4、导出路由实例对象
export default router

****************************************************************************************************************************************************************************

208、使用NavBar组件
【1】初步体验标题固定+内容展示
<template><div><!--头部区域--><van-nav-bar title="标题" fixed/><h3>aaa</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>zzz</h3></div>
</template><script>export default {name: "Home"}
</script><style scoped>.home-container {padding: 46px 0 50px 0;}
</style>

****************************************************************************************************************************************************************************

209、覆盖NavBar的默认样式
【1】会用到类选择器的知识
<template><div><!--头部区域--><van-nav-bar title="黑马头条" fixed/><h3>aaa</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3><h3>xxx</h3></div>
</template><script>export default {name: "Home"}
</script><style scoped>.home-container {padding: 46px 0 50px 0;.van-nav-bar {background-color: #007bff;}/deep/ .van-nav-bar__title {color: white;}}
</style>

****************************************************************************************************************************************************************************

210、获取列表数据
【1】主要是API接口返回json数据结构概述

****************************************************************************************************************************************************************************

211、封装utils目录下的方法
【1】配置axios
********************************************************************安装
npm i axios -S
********************************************************************src下创建utils
/*req.js*/
import axios from "axios";// 创建req即为小的axios
const req = axios.create({//  指定请求的根路径baseURL: 'https://www.escook.cn'
})export default req

****************************************************************************************************************************************************************************

212、在Home组件封装方法
【1】async...await
*********************************************************注意get请求的传参created() {this.initList();},methods: {// 获取文章列表数据的方法async initList() {const {data: res} = await req.get(`/articles`, {// 请求参数params: {_page: this.page,_limit: this.limit}})console.log(res);}}

****************************************************************************************************************************************************************************

213、封装articleAPI模块
【1】主要是每次拿数据的复用
/*文章相关的API都放在这个下面*/// 向外按需导出一个API函数
import req from "@/utils/req";export const getArticleListAPI = function (_page, _limit) {// 返回了一个promise对象return req.get(`/articles`, {// 请求参数params: {_page: _page,_limit: _limit}})
}
【2】Home User多方调用import {getArticleListAPI} from '@/api/articleAPI.js'// 获取文章列表数据的方法async initList() {const {data: res} = await getArticleListAPI(this.page, this.limit);console.log(res);}
***************************************************************************************import {getArticleListAPI} from '@/api/articleAPI.js'// 获取文章列表数据的方法async initList() {const {data: res} = await getArticleListAPI(this.page, this.limit);console.log(res);}
【3】这才是axios的真正的用法,法拉利开出法拉利的速度!!!!!!!!!

****************************************************************************************************************************************************************************

214、封装ArticleInfo组件
【1】如果不是直接被路由到的组件,就放到components文件夹下面
<template><div>ArticleInfo组件</div>
</template><script>export default {name: "ArticleInfo"}
</script><style scoped></style>
************************************************************************************<!--导入 注册 并使用ArticleInfo 组件--><ArticleInfo v-for="item in articleList" :key="item.id"></ArticleInfo>
************************************************************************************components: { //注册组件ArticleInfo},

****************************************************************************************************************************************************************************

215、升级ArticleInfo
【1】自定义属性。props: { // 自定义属性// 标题title: {type: String, default: ''},// 作者author: {type: String, default: ''},// 评论数  类型指向数组,包含可能的类型即可。commentNum: {type: [Number, String], default: 0},time: {type: String, default: ''}}
【2】父组件传值
<!--导入 注册 并使用ArticleInfo 组件--><ArticleInfo v-for="item in articleList" :key="item.id":title="item.title":author="item.aut_name":commentNum="item.comm_count":time="item.pubdate"></ArticleInfo>
【3】大写的可以改成连字符(建议,不使用也没关系)

****************************************************************************************************************************************************************************

226、图片
【1】自定义图片对象属性// 图片cover: {type: Object, default: function () {return {cover: 0}}}
【2】v-if来展示1张还是3张图片<img :src="cover.images[0]" v-if="cover.type===1"><div v-if="cover.type===3"><img :src="cover.images[0]"><img :src="cover.images[1]"><img :src="cover.images[2]"></div>

****************************************************************************************************************************************************************************

227、上拉加载更多,了解List组件
【1】List组件通过loading和finised两个变量控制加载状态
*****************************************************触发load把loading改为true
为true的时候,不会反复调用load事件,防止用户非法操作。
拿到数据后,把loading的值改为false
*****************************************************finised用来标记是否还有更多数据

****************************************************************************************************************************************************************************

218、使用List组件
【1】真牛批,大成若缺!!!
<template><div><!--头部区域--><van-nav-bar title="黑马头条" fixed/><!--导入 注册 并使用ArticleInfo 组件--><van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad"><ArticleInfo v-for="item in articleList" :key="item.id":title="item.title":author="item.aut_name":commentNum="item.comm_count":time="item.pubdate":cover="item.cover"></ArticleInfo></van-list></div>
</template><script>import {getArticleListAPI} from '@/api/articleAPI.js';import ArticleInfo from "@/components/Article/ArticleInfo";export default {name: "Home",components: { //注册组件ArticleInfo},data() {return {page: 1,limit: 10,articleList: [],loading: true, // 是否正在加载下一页finished: false // 所有数据是否加载完毕}},created() {this.initList();},methods: {// 获取文章列表数据的方法async initList() {const {data: res} = await getArticleListAPI(this.page, this.limit);// console.log(res);this.articleList = [...this.articleList, ...res]; // 旧数据在前,新数据在后this.loading = false;if (res.length === 0) { // 如果res为空 表示数据加载完毕this.finished = true;}},onLoad() {console.log("触发load事件")// 页码值甲乙this.page++;// 重新调用方法this.initList();}}}
</script><style scoped>.home-container {padding: 46px 0 50px 0;.van-nav-bar {background-color: #007bff;}/deep/ .van-nav-bar__title {color: white;}}
</style>

****************************************************************************************************************************************************************************

220、实现下拉刷新功能
【1】下拉刷新,牛批!!!!!!!!!!!!!!!!!!!<van-pull-refresh v-model="refreshing" @refresh="onRefresh">***************************************************************************<template><div><!--头部区域--><van-nav-bar title="黑马头条" fixed/><!--导入 注册 并使用ArticleInfo 组件--><van-pull-refresh v-model="refreshing" @refresh="onRefresh" :disabled="finished"><!-- :disabled="finished"控制加载完毕后的无效刷新--><van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad"><ArticleInfo v-for="item in articleList" :key="item.id":title="item.title":author="item.aut_name":commentNum="item.comm_count":time="item.pubdate":cover="item.cover"></ArticleInfo></van-list></van-pull-refresh></div>
</template><script>import {getArticleListAPI} from '@/api/articleAPI.js';import ArticleInfo from "@/components/Article/ArticleInfo";export default {name: "Home",components: { //注册组件ArticleInfo},data() {return {page: 1,limit: 10,articleList: [],loading: true, // 是否正在加载下一页finished: false, // 所有数据是否加载完毕refreshing: false}},created() {this.initList();},methods: {// 获取文章列表数据的方法async initList(refreshFlag) { // 封装的思想const {data: res} = await getArticleListAPI(this.page, this.limit);// console.log(res);if (refreshFlag) { // 下拉刷新this.articleList = [...res, ...this.articleList]; // 新在前this.refreshing = false;} else {this.articleList = [...this.articleList, ...res]; // 旧数据在前,新数据在后this.loading = false;}if (res.length === 0) { // 如果res为空 表示数据加载完毕this.finished = true;}},onLoad() {console.log("触发load事件")// 页码值加一this.page++;// 重新调用方法this.initList(false);},onRefresh() { // 下拉刷新的处理函数console.log("触发了下拉刷新")this.page++;// 头部拼接this.initList(true);}}}
</script><style scoped>.home-container {padding: 46px 0 50px 0;.van-nav-bar {background-color: #007bff;}/deep/ .van-nav-bar__title {color: white;}}
</style>

****************************************************************************************************************************************************************************

221、Vant定制主题
【1】为了覆盖默认的less变量,在main.js引入import 'vant/lib/index.less'

****************************************************************************************************************************************************************************

222、覆盖主题变量
【1】修改样式变量,但是每次都重启,开发中不用这个。
// vue.config.js
module.exports = {css: {loaderOptions: {less: {// 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。lessOptions: {modifyVars: {// 直接覆盖变量'nav-bar-background-color': 'orange',// 或者可以通过 less 文件覆盖(文件路径为绝对路径)// hack: `true; @import "your-less-file-path.less";`,},},},},},
};
【2】less是可编程的样式语言。

****************************************************************************************************************************************************************************

224、通过theme.less指定
【1】less文件
/*
theme.less
*/
@blue: #007bff;
// 覆盖NavBar的less样式
@nav-bar-background-color: @blue;
@nav-bar-title-text-color: white;
【2】less文件绝对路径指定
// vue.config.js
// webpack在进行打包的时候,底层用到了node.js   因此在vue.config.js配置文件中,可以导入并使用node.js中的核心模块
const path = require('path')
const themePath = path.join(__dirname, './src/theme.less')module.exports = {css: {loaderOptions: {less: {// 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。lessOptions: {modifyVars: {// 直接覆盖变量// 'nav-bar-background-color': 'orange',// 或者可以通过 less 文件覆盖(文件路径为绝对路径) 这个修改就不用重启服务器!!!!!!!!!!!!!!!!!!!!!!!!!hack: `true; @import "${themePath}";`,},},},},},
};

****************************************************************************************************************************************************************************

225、最后
【1】在前后端分离的情况下。而在开发过程中,我们常常需要在window系统下使用
Nginx作为Web服务器。
【2】安装完毕后,启动后在html下面放dist就完事了

****************************************************************************************************************************************************************************

226、总结
【1】vue-cli创建与开发工程化的vue项目
【2】组件化的开发思想
【3】指令、插槽、侦听器、声明周期、通讯函数来完成开发
【4】axios封装请求API接口
【5】vue-router实现单页面应用程序开发
【6】使用Vant与Element UI
【7】vue-devtools调试自己的vue项目

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

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

相关文章

4G+北斗太阳能定位终端:一键报警+倾覆报警 双重保障船舶安全

海上作业环境复杂多变&#xff0c;海上航行充满了各种不确定性和风险&#xff0c;安全事故时有发生&#xff0c;因此海上安全与应急响应一直是渔业和海运行业关注的重点。为了提高海上安全保障水平&#xff0c;4G北斗太阳能定位终端应运而生&#xff0c;它集成了一键报警和倾覆…

Edge浏览器新特性深度解析,写作ai免费软件

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

【数据结构】:链表的带环问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;数据结构 &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 链表的带环问题在链表中是一类比较难的问题&#xff0c;它对我们的思维有一个比较高的要求&#xff0c;但是这一类…

AI大模型探索之路-训练篇10:大语言模型Transformer库-Tokenizer组件实践

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…

DS:顺序表、单链表的相关OJ题训练

欢迎各位来到 Harper.Lee 的学习小世界&#xff01; 博主主页传送门&#xff1a;Harper.Lee的博客主页 想要一起进步的uu可以来后台找我交流哦&#xff01; 在DS&#xff1a;单链表的实现 和 DS&#xff1a;顺序表的实现这两篇文章中&#xff0c;我详细介绍了顺序表和单链表的…

使用LinkAI创建AI智能体,并快速接入到微信/企微/公众号/钉钉/飞书

​ LinkAI 作为企业级一站式AI Agent 智能体搭建与接入平台&#xff0c;不仅为用户和客户提供能够快速搭建具备行业知识和个性化设定的 AI 智能体的能力&#xff1b;还基于企业级场景提供丰富的应用接入能力&#xff0c;让智能体不再是“玩具”&#xff0c;而是真正能够落地应用…

PHP的数组练习实验

实 验 目 的 掌握索引和关联数组&#xff0c;以及下标和元素概念&#xff1b; 掌握数组创建、初始化&#xff0c;以及元素添加、删除、修改操作&#xff1b; 掌握foreach作用、语法、执行过程和使用&#xff1b; 能应用数组输出表格和数据。 任务1&#xff1a;使用一维索引数…

uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之使用jar包插件

前言 如果你不会编写安卓插件,你可以先看看我之前零基础的文章(uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之零基础编写安卓插件), 我们使用第三方包,jar包编写安卓插件 开始 把依赖包,放到某个模块的/libs目录(myTestPlug/libs) 还要到build…

R语言的学习—5—多元数据直观表示

1、数据读取 ## 数据整理 d3.1read.xlsx(adstats.xlsx,d3.1,rowNamesT);d3.1 #读取adstats.xlsx表格d3.1数据 barplot(apply(d3.1,1,mean)) #按行做均值条形图 barplot(apply(d3.1,1,mean),las3) barplot(apply(d3.1,2,mean)) #按列做均值图条形图 barplot(a…

C语言数据结构 ---- 单链表实现通讯录

今日备忘录: "折磨我们的往往是想象, 而不是现实." 目录 1. 前言2. 通讯录的功能3. 通讯录的实现思路5. 效果展示6. 完整代码7. 总结 正文开始 1. 前言 顺表实现通讯录: 点击~ 顺序表实现通讯录 在日常生活中&#xff0c;我们经常需要记录和管理大量的联系人信息&…

【研发管理】产品经理知识体系-组合管理

导读&#xff1a;新产品开发的组合管理是一个重要的过程&#xff0c;它涉及到对一系列新产品开发项目进行策略性选择、优先级排序、资源分配和监控。这个过程旨在确保企业能够最大化地利用有限的资源&#xff0c;以实现其战略目标。 目录 1、组合管理、五大目标 2、组合管理的…

第74天:漏洞发现-Web框架中间件插件BurpSuite浏览器被动主动探针

目录 思维导图 前置知识 案例一&#xff1a;浏览器插件-辅助&资产&漏洞库-Hack-Tools&Fofa_view&Pentestkit 案例二&#xff1a; BurpSuite 插件-被动&特定扫描-Fiora&Fastjson&Shiro&Log4j 思维导图 前置知识 目标&#xff1a; 1. 用…

基于springboot实现公司日常考勤系统项目【项目源码+论文说明】

基于springboot实现公司日常考勤系统演示 摘要 目前社会当中主要特征就是对于信息的传播比较快和信息内容的安全问题&#xff0c;原本进行办公的类型都耗费了很多的资源、传播的速度也是相对较慢、准确性不高等许多的不足。这个系统就是运用计算机软件来完成对于企业当中出勤率…

数据结构-链表OJ

1.删除链表中等于给定值 val 的所有结点。 . - 力扣&#xff08;LeetCode&#xff09; 思路一&#xff1a;遍历原链表&#xff0c;将值为val的节点释放掉 思路二&#xff1a;创建一个新链表&#xff0c;将值不为val的节点尾插到新链表中 /*** Definition for singly-linked …

2024年五一数学建模竞赛C题论文首发

基于随机森林的煤矿深部开采冲击地压危险预测 摘要 煤炭作为中国重要的能源和工业原料&#xff0c;其开采活动对国家经济的稳定与发展起着至关重要的作用。本文将使用题目给出的数据探索更为高效的数据分析方法和更先进的监测设备&#xff0c;以提高预警系统的准确性和可靠性…

智能消费记账|基于SSM+vue的大学生智能消费记账系统(源码+数据库+文档)

智能消费记账目录 基于SSMvue的大学生智能消费记账系统 一、前言 二、系统设计 三、系统功能设计 1 用户列表 2 预算信息管理 3 预算类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1…

代码随想录算法训练营DAY48|C++动态规划Part9|121.买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

文章目录 121.买卖股票的最佳时机思路CPP代码 122.买卖股票的最佳时机II思路CPP代码 123.买卖股票的最佳时机III思路CPP代码 121.买卖股票的最佳时机 力扣题目链接 文章讲解&#xff1a;121.买卖股票的最佳时机 视频讲解&#xff1a;动态规划之 LeetCode&#xff1a;121.买卖股…

Android 音视频基础知识

本系列文章会介绍两个 Android NDK Demo&#xff0c;拉流端会实现一个基于 FFmpeg 的视频播放器 Demo&#xff0c;推流端会实现一个视频直播 Demo&#xff0c;当然在做 Demo 之前会介绍音视频的基础知识。以下是本系列文章的目录&#xff1a; Android 音视频基础知识 Android 音…

抢先体验:MacOS成功安装PHP8.4教程

根据官方消息&#xff0c;PHP 8.4将于2024年11月21日发布。它将通过三个 alpha 版本、三个 beta 版本和六个候选版本进行测试。 这次的重大更新将为PHP带来许多优化和强大的功能。我们很高兴能够引导您完成最有趣的更新升级&#xff0c;这些更改将使我们能够编写更好的代码并构…

Mac brew安装Redis之后更新配置文件的方法

安装命令 brew install redis 查看安装位置命令 brew list redis #查看redis安装的位置 % brew list redis /usr/local/Cellar/redis/6.2.5/.bottle/etc/ (2 files) /usr/local/Cellar/redis/6.2.5/bin/redis-benchmark /usr/local/Cellar/redis/6.2.5/bin/redis-check-ao…