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是所有的父,其他的都是子。
 <Goods
                v-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-->
        <Goods
                v-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后重命名为res
                const {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 = axios

new 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 = axios

new 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是路由的导航对象。
***************************************开启props
  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}
      ]
    },
  ]
***************************************接收
  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 = false

new 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') {
          //存储token
          localStorage.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() {
        //清空token
        localStorage.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 = false

new 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 = false

new 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.mfbz.cn/a/589021.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

您想拥有一个属于你自己的GPT-3.5-turbo吗?来吧,开始行动起来吧!!!

背景: 在2024年4月的时候,openai公司宣布GPT-3.5-turbo免费使用,无需注册!!! 多么激动人心的消息啊!!! 但是,如何你想申请一个openai api key的时候,发现调用失败,直接报Rate Limit!!! 无语了!!! 不过没关系,我们另辟捷径!!! 下面就开始我的表演啦…

python可视化学习笔记折线图问题-起始点问题

问题描述&#xff1a; 起始点的位置不对 from pyecharts.charts import Line import pyecharts.options as opts # 示例数据 x_data [1,2,3,4,5] y_data [1, 2, 3, 4, 5] # 创建 Line 图表 line Line() line.add_xaxis(x_data) line.add_yaxis("test", y_data) li…

【全网最全】2024五一数学建模B题论文+前四问代码多种保奖进阶思路+建模过程+代码+数据处理+论文写作技巧等(后续会更新)

一定要点击文末的卡片&#xff0c;那是获取资料的入口&#xff01; 点击链接加入群聊【2024五一数学建模】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&khoTDlhAS5N_Ffp-vucfG5WjeeJFxsWbz&authKey7oCSHS25VqSLauZ2PpiewRQ9D9PklaCxVS5X6i%2BAkDrey992f0t15…

【hackmyvm】vivifytech靶机

渗透思路 信息收集端口扫描端口服务信息目录扫描爆破hydra--sshgit提权 信息收集 ┌──(kali㉿kali)-[~] └─$ fping -ag 192.168.9.0/24 2>/dev/null 192.168.9.119 --主机 192.168.9.164 --靶机个人习惯&#xff0c;也方便后续操作&#xff0c;将IP地址赋值给一个变…

两院院士泌尿外科专家吴阶平教授

吴阶平&#xff08;1917-2011&#xff09;&#xff0c;男&#xff0c;江苏常州人&#xff0c;1933年天津汇文中学毕业&#xff0c;保送到北平燕京大学医预科&#xff0c;1937年毕业于北平燕京大学获理学士学位&#xff0c;1942年毕业于北平协和医学院获医学博士学位&#xff0c…

使用 Langchain、Langfuse、Nemo-gaurdrails、RAGAs构建 RAG 管道并进行监控和评估

原文地址:build-end-to-end-rag-pipeline-with-monitoring-and-evaluation-using-langchain-azure-ai-search 2024 年 4 月 21 日 介绍 使用现代的LLM框架,如Langchain或llamaindex,可以迅速搭建一个用于 RAG 的管道,通常只需编写大约5-6行代码。然而,若要构建一个适用于生…

短视频素材去哪里搬运?短视频素材有哪些类型?

在这个数字化和视觉传达至关重要的时代&#xff0c;选择合适的视频素材对于提升视频内容的吸引力和观众参与度至关重要。无论您是一名广告制片人、社交媒体经理还是独立视频制作者&#xff0c;以下这些精选的视频素材网站将为您提供从高清视频到特效资源的全面支持&#xff0c;…

HSDB使用教程

HSDB&#xff1a;Hostspot Debugger&#xff0c;JVM内置的工具&#xff0c;用于深入分析JVM运行时的内部状态 启动HSDB java -cp D:/tools/jdk-1.8/lib/sa-jdi.jar sun.jvm.hotspot.HSDB 获取进程id jps 连接到指定进程 查找类 通过查询查找对象 输入查询语句 select d from …

算法复杂度分析:揭秘隐藏的计算之谜

复杂度 算法的复杂度指的是执行该算法的程序在运行时所需要的时间和空间资源。时间复杂度不是代码真正的时间&#xff0c;而是数据规模的增长所表达的趋势。 算法的复杂度分析分为时间复杂度和空间复杂度。一般我们说的多的是算法的时间复杂度&#xff0c;希望通过较少时间执行…

iOS 实现视图遮罩效果

有时候&#xff0c;我们会遇到这种需求&#xff0c;只讲视图的某个部分展示出来 这时候&#xff0c;我们可以通过设置该视图layer.mask layerb来实现&#xff0c;需要注意的是&#xff0c;这里的layerb必须要设置backgroundColor&#xff0c;渐变layer有colors,否则达不到效果…

ubuntu sudo apt-get install neo4j 配置安装与设置远程访问

文章目录 下载Adding the Debian repositoryInstalling Neo4j安装流程设置远程访问 下载 neo4j 官方的下载地址&#xff0c;进入页面之后&#xff0c;往下滑&#xff1a; https://neo4j.com/deployment-center/#community 点击 Visit https://debian.neo4j.com/ Adding the …

链表(数组实现的伟大二踢脚)

一.链表与数组 链表作为 C 语言中一种基础的数据结构&#xff0c;在平时写程序的时候用的并不多&#xff0c;但在操作系统里面使用的非常多。不管是RTOS还是Linux等使用非常广泛&#xff0c;所以必须要搞懂链表&#xff0c;链表分为单向链表和双向链表&#xff0c;单向链表很少…

2024.5.1【项目测试报告】模拟微信实现网页聊天室

目录 项目介绍 核心功能 额外拓展 核心技术 项目页面设计 注册页面 登录页面 找回密码页面 网页聊天室页面 个人中心页面 测试计划 功能测试 注册页面 登录页面 找回密码页面 个人中心页面 网页聊天室页面 自动化测试 单例驱动 获取屏幕截图 注册页面自动化测…

GPG的使用

这里写自定义目录标题 安装加密程序生成加密密钥怎么备份自己的密钥就可以使用公钥加密邮件信息了 安装加密程序 下载gpg4win&#xff1a; https://www.gpg4win.org/index.html 免费的&#xff0c;如果使用的是苹果电脑&#xff0c;使用https://gpgtools.org/。 如果是linux&a…

【精选文献】JAG|基于时序Sentinel-1 SAR影像小农耕作区烟草空间分布制图

目录 文章简介 01 文章摘要 02 研究背景、目标及创新点 03 研究区域与数据集 04 研究方法 05 研究结果 06 研究讨论 07 研究结论 08 文章引用 文章简介 论文名称&#xff1a;Mapping tobacco planting areas in smallholder farmlands using Phenological-Spatial-Te…

golang判断通道chan是否关闭的2种方式

chan通道在go语言的办法编程中使用频繁&#xff0c;我们可以通过以下2种方式来判断channel通道是否已经关闭&#xff0c;1是使用 for range循环&#xff0c;另外是通过 for循环中if 简短语句的 逗号 ok 模式来判断。 示例代码如下&#xff1a; //方式1 通过for range形式判断…

LNMP部署wordpress

1.环境准备 总体架构介绍 序号类型名称外网地址内网地址软件02负载均衡服务器lb0110.0.0.5192.168.88.5nginx keepalived03负载均衡服务器lb0210.0.0.6192.168.88.6nginx keepalived04web服务器web0110.0.0.7192.168.88.7nginx05web服务器web0210.0.0.8192.168.88.8nginx06we…

Nodejs -- 流程控制库

流程控制库 尾触发和next 尾触发最多的应用是在Connect的中间件 var app connect() app.use(connect.staticCache()) app.use(connect.static(__dirname /public)) app.use(conect.cokkieParser()) app.use(connect.session()) app.use(connect.query()) app.use(connect.…

跨平台终端软件——quardCRT

作为一个技术栈比较复杂的程序&#xff0c;工作常常会在windows/linux/macos等不同的平台切换开发&#xff0c;开发过程中最常用的就是终端工具了&#xff0c;一个趁手的终端可以成倍的提高工作效率&#xff0c;因此我一直希望能找个一个跨平台体验一致无缝切换的终端软件&…

Unity Audio Filter 入门

概述&#xff1a; 如果你在你项目中需要一些特殊的声音效果&#xff0c;那这部分声音过滤器的部分一定不要错过喔&#xff0c;让我们来学习这部分的内容吧&#xff01; 这部分理论性比较强&#xff0c;认真看我的注解哈&#xff0c;我尽量解释的易懂一点。 Audio Chorus Filter…