十六、状态管理——Vuex(4)

news2025/1/12 10:34:51

本章概要

  • 表单处理
  • Vuex 与组合 API
  • 模块

16.8 表单处理

在表单控件上通常会使用 v-model 指令进行数据绑定,如果绑定的数据是 Vuex 中的状态数据,就会遇到一些问题。看以下代码:

form.html

<div id="app">
    <my-component></my-component>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script src="https://unpkg.com/vuex@next"></script>
<script>
    const app = Vue.createApp({});
    const store = Vuex.createStore({
        state(){
            return {
                message:"gogogo"
            }
        },
        mutatioins:{
            updations:{
                updateMessage(state,msg){
                    state.message = msg;
                }
            }
        }
    })

    app.component('myComponent',{
        component:Vuex.mapState([
            'message'
        ]),
        template:'<input type="text" v-model="message">'
    })

    app.use(store).mount('#app')
</script>

当在文本控件中输入值时,v-model 会试图直接修改 message 属性的值,这将引发一个警告:[Vue warn] :Write operation failed: computed property “message” is readonly ,这是由 v-model 的数据双向绑定机制决定的。我们希望在用户输入数据时,调用 mutation() 处理函数修改 store 中的状态 message ,从而实现计算属性 message 的更新,那么可以采用两种方式来实现。
(1)通过 input 元素使用 v-bind 绑定 value 属性,然后使用 v-on 监听 input 或 change 事件,在事件处理函数中提交 mutation 。修改 form.html 的代码,如下:

...
app.component('myComponent',{
  component:Vuex.mapState([
    'message'
  ]),
  methods:{
    updateMessage(e){
      this.$store.commit('updateMessage',e.target.value)
    }
  },
  template:'<input type="text" :value="message" @input="updateMessage">'
})
...

这种方式相当于自己实现了 v-model 指令,代码有些繁琐。如果还是想用 v-model,那么可以使用第二种方式。
(2)计算属性可以提供一个 setter 用于计算属性的修改。可以在 set() 函数中提交 mutations。如下:

...
app.component('myComponent',{
    computed:{
        message:{
            get() {
                return this.$store.state.message;
            },
            set(value){
                this.$store.commit('updateMessage',value)
            }
        }
    },
    template:'<input type="text" v-model="message">'
})
...

16.9 Vuex 与组合 API

要在 setup() 函数中访问 store,可以调用 useStore() 函数,这与在选项 API 中通过 this.store 访问 store 是等价的。如下:

import {useStore} from 'vuex'

export default {
  setup(){
    const store = useStore()
  }
}

如果要访问 state 和 getters ,则需要使用 computed() 函数创建计算属性,以保持响应性,这相当于使用选项 API 创建计算属性。如下:

import { computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup(){
    const store = useStore()

    return {
      // 在computed() 函数中访问状态
      count:computed(() => store.state.count),
      // 在conputed() 函数中访问 getters
      double:computed(() => store.getters.double)
    }
  }
}

要访问 mutation 和 action ,只需要在 setup() 函数中调用 store 对象的 commit() 和 dispatch() 函数,如下:

import { useStore } from 'vuex'

export default{
  setup(){
    const store = useStore()

    return {
      // 访问 mutation
      increment:() => store.commit('increment'),

      // 访问 action
      asyncIncrement:() => store.dispatch('asyncIncrement')
    }
  }
}

16.10 模块

Vuex 使用单一状态树,应用程序的所有状态都包含在一个大的对象中,当应用变得复杂时,store 对象就会变得非常臃肿。
为了解决这个问题,Vuex 允许将 store 划分为多个模块,每个模块都可以包含自己的 state、mutations、actions、getters 及嵌套的子模块。例如:

const moduleA = {
  state:() => ({...}),
  mutations:{...},
  actions:{...},
  getters:{...}
}

const moduleB = {
  state:() => ({}),
  mutations:{...},
  actions:{...}
}

const store = createStore({
  modules:{
    a:moduleA,
    b:moduleB
  }
})

store.state.a   // -> moudleA 的状态
store.state.b   // -> moudleB 的状态

对于模块内部的 mutations 和 getters ,接收的第1个参数是模块的局部状态对象。如下:

const moduleA = {
  state:() => ({
    count:0
  }),
  mutations:{
    increment(state){
      // state 对象是局部模块状态
      state.count++
    }
  },

  getters:{
    doubleCount(state){
      return state.count * 2
    }
  }
}

同样地,对于模块内部的 actions ,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState。如下:

const moduleA = {
  // ...
  actions:{
    incrementIfOddOnRootSum({state,commit,rootState}){
      if((state.count + rootState.count) % 2 === 1 ){
        commit('increment')
      }
    }
  }
}

对于模块内部的 getters ,根节点状态将作为第 3 个参数暴露出来。如下:

const moduleA = {
  // ...
  getters:{
    sumWithRootCount(state,getters,rootState){
      return state.count + rootState.count
    }
  }
}

在一个大型项目中,如果 store 模块划分较多,Vuex 建议项目结构按照以下形式组织。

|—— store
    	|———— index.js   # 组装模块并导出 store 的地方
    	|———— actions.js   # 根级别的 actions
    	|———— mutations.js   # 根级别的 mutations
    	|———— modules   
          	|————cart.js   # 购物车模块
          	|————products.js   # 产品模块

在默认情况下,模块内部的 action、mutation 和 getters 是注册在全局命名空间下的,这使多个模块能够对同一 mutation 或 action 做出响应。
如果希望模块具有更高的封装度和复用性,则可以通过添加 namespaced:true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 mutation、action 和 getters 都会根据模块注册的路径自动命名。
例如:

const store = createStore({
  modules:{
    account:{
      namespaced:true,
      // 模块内容(module assets)
      // 模块的状态已经是嵌套的,使用 namespaced 选项不会对其产生影响
      state:() => ({...}),
      getters:{
        isAdmin() {...} // -> gettters['account/isAdmin']
      },
      actions:{
        login() {...} // -> dispatch('account/login')
      },
      mutations:{
        login(){...} // -> commit('account/login')
      },

      // 嵌套模块
      modules:{
        // 继承父模块的命名空间
        myPage:{
          state:() => ({...}),
          getters:{
            profile(){...} // -> getters['account/profile']
          }
        },
        // 进一步嵌套命名空间
        posts:{
          namespaced:true,
          state:()=>({...}),
          getters:{
            popular(){...} //-> getters['account/post/popular']
          }
        }
      }
    }
  }
})

启用了命名空间的 getters 和 actions 会接收本地的 getters、dispatch 和 commit 。换句话说,在同一模块内使用模块内容(module assets)时不需要添加前缀。在命名空间和非命名空间之间切换不会影响模块内的代码。
在带有命名空间的模块内如果要使用全局 state 和 getters,rootState 和 rootGetters 会作为第 3 和 第 4 个参数传入 getter() 函数,也会通过 context 对象的属性传入 action() 函数。如果在全局命名空间内分发 action 或提交 mutation,则将 { root:true } 作为第 3 个参数传给 dispatch() 或 commit() 方法即可。如下:

modules:{
    foo:{
        namespaced:true,
        getters:{
            // 在foo模块中,getters已经被本地化
            // 使用getters 的第三个参数 rootState 访问全局state
            // 使用 getters 的第四个参数 rootGetters 访问全局 getters
            someGetter(state,getters,rootState,rootGetters){
                getters.someOtherGetter   // -> 'foo/someOtherGetter'
                rootGetters.someOtherGetter   // -> 'someOtherGetter'
                rootGetters['bar/someOtherGetter']   // -> 'bar/someOtherGetter'
            },
            someOtherGetter:state => {...}
        },
        actions:{
            // 在这个模块中,dispatch 和 commit 也被本地化了
            // 他们可以接收 root 选项以访问dispatch 或 commit
            someAction({dispatch,commit,getters,rootGetters}){
                getters.someGetter   // -> 'foo/someGetter'
                rootGetters:someGetter   // -> 'someGetter'
                rootGetters['bar/someGetter']   // -> 'bar/someGetter'

                dispatch('someOtherAction')   // -> 'foo/someOtherAction'
                dispatch('someOtherAction',null,{root:true})   // -> 'someOtherActioin'

                commit('someMutation')   // -> 'foo/someMutation'
                commit('someMutation',null,{root:true})   // -> 'someMutation'
            },
            someOtherAction(ctx,payload){...}
        }
    }
}

如果需要在带命名空间的模块内注册全局 action,可以将其标记为 root:true ,并将这个 action 的定义放到函数 handler() 中。例如:

{
  actions:{
    someOtherAction({dispatch}){
      dispatch('someAction')
    }
  },
  modules:{
    foo:{
      namespaced:true,
      actioins:{
        someAction:{
          root:true,
          handler(namespacedContext,payload){...}   // -> 'someAction'
        }
      }
    }
  }
}

在组件内使用 mapState() 、mapGetters()、mapActions() 和 mapMutations() 这些辅助函数绑定带命名空间的模块时,写起来可能比较烦琐。如下:

computed:{
  ...mapState({
    a:state => state.some.nested.module.a,
    b:state => state.some.nested.module.b
  }),
  ...mapGetters([
    'some/nested/module/someGetter',   // -> this['some/nested/module/someGetter']
    'some/nested/module/someOtherGetter'   // -> this['some/nested/module/someOtherGetter']
  ])
},
methods:{
  ...mapActions([
    'some/nested/module/foo',   // -> this['some/nested/module/foo']()
    'some/nested/module/bar'   // -> this['some/nested/module/bar']()
  ])
}

在这种情况下,可以将带命名空间的模块名字作为第 1 个参数传递个上述函数,这样所有绑定都会自动使用该模块作为上下文。于是上面的例子可以简化为如下代码:

computed:{
  ...mapState('some/nested/module',{
    a:state => state.a,
    b:state => state.b
  }),
  ...mapGetters('some/nested/module',[
    'someGetter',   // -> this.someGetter
    'someOtherGetter'   // -> this.someOtherGetter
  ])
},
methods:{
  ...mapActions('some/nested/module',[
    'foo',   // -> this.foo()
    'bar'   // -> this.bar()
  ])
}

此外,还可以使用 createNamespacedHelpers() 方法创建命名空间的辅助函数。它返回一个对象,该对象有与给定命名空间值绑定的新的组件绑定辅助函数。如下:

import { createNamespacedHelpers } from 'vuex'

const { mapState,mapActions } = createNamespacedHelpers('some/nested/module')

export default{
  computed:{
    computed:{
      // 在 some/nested/module 中查找
      ...mapState({
        a:state => state.a,
        b:state => state.b
      })
    },
    methods:{
      // 在some/nested/module 中查找
      ...mapActions([
        'foo',
        'bar'
      ])
    }
  }
}

为了对待带命名空间的模块的访问有更直观的认知,下面给出一个简单的示例。
先给出两个带命名空间的模块定义。如下:

const ModuleA = {
  namespaced:true,
  state(){
    return {
      message:'hello vue'
    }
  },
  mutations:{
    updateMessage(state,newMsg){
      state.message = newMsg;
    }
  },
  actions:{
    changeMessage({commit},newMsg){
      commit('updateMessage',newMsg);
    }
  },
  getters:{
    reversedMessage(state){
      return state.message.split('').reverse().join('');
    }
  }
}

const ModuleB = {
  namespaced:true,
  state(){
    return{
      count:0
    }
  },
  mutations:{
    increment:{
      state.count++
    }
  }
}

ModuleA 和 ModuleB 都使用了 namespaced 选项并设置为 true,从而变成具有命名空间的模块。
ModuleA 中的 state、mutations、actions 和 getters 一个都不少,简单起见,ModuleB 只有 state 和 mutations。
接下来在 Store 实例中注册模块。如下:

const store = Vuex.createStore({
  modules:{
    msg:ModuleA,
    another:ModuleB
  }
})

根据模块注册时的名字访问模块。例如,要访问 ModuleA 中的状态,应该使用 msg 名字访问。如下:

this.$store.state.msg.message
// 或者
this.$store.state['msg'].message

模块注册时,也可以根据应用的需要,为名字添加任意前缀。如下:

const store = Vuex.createStore({
  modules:{
    'user/msg':ModuleA,
    another:ModuleB
  }
})

这是要访问 ModuleA 中的状态,需要使用 user/msg。如下:

this.$store.state['user/msg'].message

最后看在组件内如何访问带命名空间的模块。如下:

Modules.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
</head>

<body>
    <div id="app">
        <my-component></my-component>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vuex@next"></script>
    <script>
        const app = Vue.createApp({});
        const ModuleA = {
            namespaced: true,
            state() {
                return {
                    message: 'Hello Vue.js'
                }
            },
            mutations: {
                updateMessage(state, newMsg) {
                    state.message = newMsg;
                }
            },
            actions: {
                changeMessage({ commit }, newMsg) {
                    commit('updateMessage', newMsg);
                }
            },
            getters: {
                reversedMessage(state) {
                    return state.message.split('').reverse().join('');
                }
            }
        }

        const ModuleB = {
            namespaced: true,
            state() {
                return {
                    count: 0
                }
            },
            mutations: {
                increment(state) {
                    state.count++;
                }
            }
        }
        const store = Vuex.createStore({
            modules: {
                msg: ModuleA,
                another: ModuleB
            }
        })

        app.component('MyComponent', {
            data() {
                return {
                    message: ''
                }
            },
            computed: {
                ...Vuex.mapState({
                    msg() {
                        return this.$store.state['msg'].message;
                    }
                }),
                // 将模块的名字作为第一个参数传递给mapState
                ...Vuex.mapState('another', [
                    // 将this.count映射为 store.state['another'].count
                    'count',
                ]),
                reversedMessage() {
                    return this.$store.getters['msg/reversedMessage'];
                }
            },
            methods: {
                // 将模块的名字作为第一个参数传递给mapMutations
                ...Vuex.mapMutations('msg', [
                    // 将this.updateMessage()映射为this.$store.commit('msg/increment')
                    'updateMessage',
                ]),
                add() {
                    this.$store.commit('another/increment')
                },
                changeMessage() {
                    this.$store.dispatch('msg/changeMessage', this.message)
                },
                // 等价于
                /*...Vuex.mapActions('msg', [
                  // 将this.changeMessage(message)映射为this.$store.dispatch('msg/changeMessage', message)
                    'changeMessage',
                ]),*/

            },
            template: `
	        <div>
	          <p>
	            <span>消息:{{ msg }}</span>
	            <span>反转的消息:{{ reversedMessage }}</span>
	          </p>
	          <p>
	            <input type="text" v-model="message">
	            <button @click="changeMessage()">修改内容</button>
	          </p>
	          <p>
	            <span>计数:{{ count }}</span>
	            <button @click="add">增加计数</button>
	          </p>
	        </div>`
        });

        app.use(store).mount('#app')
    </script>
</body>

</html>

如果使用注释中的代码,需要将【修改内容】按钮的代码修改为如下代码:

<button @click="changeMessage(message)">修改内容</button>

从上述代码可以看出,对于带命名空间的模块访问,最简单的方式是使用辅助函数进行映射,并将模块的名字作为第一个参数传递进去,这样不仅简答,而且不会出错。
以上页面渲染的效果如下:
在这里插入图片描述

下面将购物车程序按模块组织,首先在 store 目录下新建一个 modules 文件夹,在该文件夹下继续新建一个文件 cart.js,这个文件将作为购物车的模块文件,所有与购物车相关的状态管理都放到 cart 模块中。
如果以后还有其他模块,如 users 模块,可以在 modules 目录下新建 users.js 文件,所有与用户相关的状态管理可以放到 users 模块中。
将 store/index.js 文件中与购物车状态管理相关的代码复制到 cart.js 中,并指定选项 namespaced:true ,让cart 成为带命名空间的模块。如下:

store/modules/cart.js

import books from '@/data/books.js'

const cart = {
    namespaced:true,
    state(){
        return {
            items:books
        }
    },
    mutations:{
        pushItemToCart (state,book){
            state.items.push(book);
        },
        deleteItem (state,id){
            // 根据提交的 id 载荷,查找是否存在相同 id 的商品,返回商品的索引
            let index = state.items.findIndex(item => item.id === id);
            if(index>0){
                state.items.splice(index,1);
            }
        },
        incrementItemCount(state,{id,count}){
            let item = state.items.find(item => item.id === id);
            if(item){
                item.count += count; //如果count 为1,则加1;如果 count 为 -1 则减 1
            }
        }
    },
    getters:{
        cartItemPrice(state){
            return function (id){
                let item = state.items.find(item => item.id === id);
                if(item){
                    return item.price * item.count;
                }
            }
        },
        cartTotalPrice(state){
            return state.items.reduce((total,item) => {
                return total + item.price * item.count;
            },0)
        }
    },
    actions:{
        addItemToCart(context,book){
            let item = context.state.items.find(item => item.id === book.id);
            // 如果添加的商品已经再购物车中存在,则只增加购物车中商品的数量
            if(item){
                context.commit('incrementItemCount',book);
            }
            // 如果添加的商品是新商品,则加入购物车中
            else{
                context.commit('pushItemToCart',book);
            }
        }
    }
}

export default cart

接下来修改 store 目录下的 index.js 文件,使用mmodules 选项注册 cart 模块。如下:

store/index.js

import { createStore } from "vuex";
import cart from '@/store/modules/cart.js'

const store = createStore({
    modules:{
        cart
    }
})

export default store;

最后修改 Cart.vue ,将带命名空间的模块名字 cart 作为第一个参数传递给 mapXxx() 等辅助函数,让所有绑定都自动使用 cart 模块作为上下文。修改后的代码如下:

cart.vue

<template>
    <div>
        <table>
            <tr>
                <td>商品编号</td>
                <td><input type="text" v-model.number="id" /></td>
            </tr>
            <tr>
                <td>商品名称</td>
                <td><input type="text" v-model.number="title" /></td>
            </tr>
            <tr>
                <td>商品价格</td>
                <td><input type="text" v-model.number="price" /></td>
            </tr>
            <tr>
                <td>数量</td>
                <td><input type="text" v-model.number="quantity" /></td>
            </tr>
            <tr>
                <td colspan="2"><button @click="addCart">加入购物车</button></td>
            </tr>
        </table>
        <table>
            <thead>
                <tr>
                    <th>编号</th>
                    <th>商品名称</th>
                    <th>价格</th>
                    <th>数量</th>
                    <th>金额</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="book in books" :key="book.id">
                    <td>{{ book.id }}</td>
                    <td>{{ book.title }}</td>
                    <td>{{ book.price }}</td>
                    <td>
                        <button :disabled="book.count === 0" @click="increment({ id: book.id, count: -1 })">-</button>
                        {{ book.count }}
                        <button @click="increment({ id: book.id, count: 1 })">+</button>
                    </td>
                    <td>{{ itemPrice(book.id) }}</td>
                    <td><button @click="deleteItem(book.id)">删除</button></td>
                </tr>
            </tbody>
        </table>
        <span>总价:¥{{ totalPrice }}</span>
    </div>
</template>
<script>
import { mapMutations, mapState, mapGetters,mapActions } from 'vuex';

export default {
    data() {
        return {
            id: null,
            title: '',
            price: '',
            quantity: 1
        }
    },
    computed: {
        // books() {
        //     return this.$store.state.items;
        // },
        ...mapState('cart',{
            books: 'items'
        }),
        ...mapGetters('cart',{
            itemPrice: 'cartItemPrice',
            totalPrice: 'cartTotalPrice'
        }),
    },
    methods: {
        ...mapMutations('cart',{
            addItemToCart: 'pushItemToCart',
            increment: 'incrementItemCount'
        }),
        ...mapMutations('cart',[
            'deleteItem'
        ]),
        ...mapActions('cart',[
            'addItemToCart'
        ]),
        addCart() {
            // this.$store.commit('pushItemToCart', {
            this.addItemToCart({
                id: this.id,
                title: this.title,
                price: this.price,
                count: this.quantity
            })
            this.id = '';
            this.title = '';
            this.price = '';
        },
    }
}
</script>
<style scoped>
div {
    width: 800px;
}

table {
    border: 1px solid black;
    width: 100%;
    margin-top: 20px;
}

th {
    height: 50px;
}

th,
td {
    border-bottom: 1px solid #ddd;
    text-align: center;
}

span {
    float: right;
}
</style>

此时再次运行项目,一切正常。如下:
在这里插入图片描述

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

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

相关文章

一场衍生于产业的深度变革正在上演,总结起来就是产业互联网的变革

毫无疑问的是&#xff0c;一场衍生于产业的深度变革正在上演。在这样一场深度变革之中&#xff0c;曾经看似无法改变的存在&#xff0c;有了进化的可能性&#xff1b;曾经让玩家们望而却步的领域&#xff0c;有了进军的可能性。如果对这样一场深度变革进行一次总结的话&#xf…

vanishing point detection in autopilot

1. 概述 消失点一种直观的解释是图像中的平行线的交点&#xff0c;也就如下图中路面边界绘制的直线在图像中的交点。 这样的点在自动驾驶场景下可以为解析车辆状态提供一些信息&#xff0c;比如较为常规的运用便是用于车辆的pitch角度。在传统方法中会通过如霍夫算子检测图片…

2022稳定学习年度研究进展系列报告丨精华观点总结

近年来&#xff0c;在独立分布假设的前提下&#xff0c;机器学习模型的表现越来越好。但在实际应用场景中&#xff0c;数据本身却具有很强的异质性和差异性&#xff0c;这就对模型的泛化能力产生了较高的要求。为了解决分布外泛化问题&#xff0c;稳定学习应运而生。12月28日&a…

Python计算机视觉:人脸识别

讲明一下:并没有实现人脸识别的算法,只是利用人脸特征文件(文件从官网上下载),从而进行人脸识别,总感觉识别出来的效果还是有问题的,如:图片最好是人脸的正脸。 1. 人脸特征文件下载 直接去github或者gitee(建议gitee)上去搜索opencv即可,如下: 选择第一个直接进入即…

一篇文章带你了解——Linux中 文件权限 和 粘滞位的 概念 / 作用 及 实现方法

粘滞位首言用户权限文件权限文件类型分类文件访问者的分类实际解读文件权限文件权限设置方法为啥要有文件权限为啥要有粘滞位粘滞位的好处如何添加粘滞位首言 要了解粘滞位&#xff0c;首先得了解文件及用户权限 用户权限 Linux下有两种用户&#xff1a;超级用户&#xff08…

共享内存原理与使用

共享内存是System V版本的最后一个进程间通信方式。共享内存&#xff0c;顾名思义就是允许两个不相关的进程访问同一个逻辑内存&#xff0c;共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一…

vite学习详解

简介 前言 之前vite2刚出的时候其实已经自学过一波&#xff0c;但是老实说学起来完全不入脑&#xff0c;一方面本来这方面的基础就很差&#xff08;指项目配置&#xff09;&#xff0c;另一方面学的时候没有跟着去动手&#xff0c;纯理论的学那完全就是越看越困。最后就是急躁…

java书店带商家商城书店多单商书店系统源码

简介 Java ssm开发的多商家书店商城&#xff0c;用户可以浏览商品&#xff0c;加入购物车&#xff0c;直接下单支付&#xff0c;在我的个人中心里可以管理自己的订单&#xff0c;收货地址&#xff0c;编辑资料等&#xff0c;还可以申请开店&#xff0c;店铺开通后可以发布商品…

C++--list

前言 这篇文章对于理解封装是非常有帮助的&#xff0c;list的底层是双向链表结构&#xff0c;我们在学习数据结构是就已经学过了双向链表&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一个元素。因为list独特的结…

nsis打包程序自动生成的快捷方式打不开

nsis 打包程序自动生成的快捷方式打不开 一: 问题描述: nsis 打包程序自动生成的快捷方式打不开, 报的是: 打不开数据库 , 但是在目录下双击exe 是能够打开的 一: 问题推导: 我是先右击自动生成的快捷方式 选择打开文件所在位置, 我发现确实是 我想要那个exe 的所在位置然后…

Zynq PL端调用PS端的时钟

ZYNQ PS端最多可以分配4个时钟供给PL端使用&#xff0c;见下图。 本文的目的&#xff1a;在XCZU21DR环境下&#xff0c;PS给PL提供一个100MHz的时钟&#xff0c;PL端根据此时钟产生1S信号&#xff0c;点亮LED。 添加&配置Zynq UltraScale MPSoc IP 双击该IP&#xff0c;在…

【C++】C++入门知识(一)

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《C》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 1.C关键字 2.命名空间 2.1局部变量和全局变量 2.2命名空间的概念及使用 2.3…

本硕985计算机,34岁的字节大头兵,上司很器重我,给我加薪不少,但国企也欢迎我,好犹豫该不该去国企!...

互联网VS国企&#xff0c;该怎么选&#xff1f;这是一位34岁的字节程序员面临的选择&#xff1a;在头条是2-2大头兵&#xff0c;本硕985计算机&#xff0c;国企还是比较欢迎他的。原本的想法是在私企干几年&#xff0c;如果干不成管理就去国企。如今没当成管理&#xff0c;但上…

【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式省赛(第二场)程序设计试题及其题解

原题展示 &#x1f4c4; 本试题目的是制作一个商品管理系统&#xff0c;其主要功能为&#xff1a;购买商品、增加商品储量、调节商品价格、查询商品价格&#xff0c;并且能够保存改变后的商品数量与商品价格&#xff0c;总体上看跟第一场的试题差不多&#xff0c;下面就让我们一…

Python Selenium 获取动态网页指定元素的超链接

Python Selenium 获取动态网页指定元素的超链接前言前提条件相关介绍实验环境获取动态网页指定元素的超链接目标网址代码实现前言 本文是个人使用Python Selenium 获取动态网页指定元素的超链接的电子笔记&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评…

详解浮点数在内存中的存储

目录 前言 一、 32 位单精度浮点数在内存中的存储 1.1 - 符号位 sign 1.2 - 偏移后的指数位 biased exponent 1.3 - 尾数位 fraction&#xff08;mantissa&#xff09; 二、64 位双精度浮点数在内存中的存储 三、浮点数的比较 前言 计算机内部实际上只能存储和识别二进制…

IPV6相关

目录 一、IPV6地址组成与专业术语 1.基础分类 2.本地链路地址范围区域概念 3.本地环回地址 二、centos配置IPV6地址 1.终端命令配置IPV6地址和网关 2.文件中配置IPV6地址 三、IPV6连通测试 1.全局单播地址进行ping 一、IPV6地址组成与专业术语 1.基础分类 IPv6基础知…

对话开发者:Serverless 落地的困境与破局

作者 | 阿里云开发者社区、InfoQ 从 2012 年提出 Serverless 到今年 2022 年刚好十年。 过去十年&#xff0c;上云是确定性趋势&#xff0c;在这个阶段企业一开始的关注点在于如何实现平滑上云。随着越来越多的企业上云&#xff0c;甚至很多企业系统第一天就是在云上构建&…

7-2 出生年

以上是新浪微博中一奇葩贴&#xff1a;“我出生于1988年&#xff0c;直到25岁才遇到4个数字都不相同的年份。”也就是说&#xff0c;直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求&#xff0c;自动填充“我出生于y年&#xff0c;直到x岁才遇到n个数字都不相同的…

【数据结构与算法——C语言版】5. 排序算法(1)——冒泡排序

前言 上篇文章【数据结构与算法——C语言版】4. 排序算法&#xff08;1&#xff09;——选择排序我们介绍了排序算法中的选择排序&#xff0c;其时间复杂度是O(n2)&#xff0c;本篇文章我们将介绍另一种同样时间复杂度是O(n2)的排序算法——冒牌排序&#xff0c;这两种算法思路…