前端学习笔记(15)-Vue3状态管理store及Vuex的使用

news2025/7/17 13:37:49

1.状态管理

2.用响应式API做简单状态管理

3.Vuex基础

4.Vuex 核心概念

5. Vuex+sessionStorage实现数据存储


1.状态管理

理论上来说,每一个 Vue 组件实例都已经在“管理”它自己的响应式状态了。我们以一个简单的计数器组件为例:

<script setup>
import { ref } from 'vue'

// 状态
const count = ref(0)

// 动作
function increment() {
  count.value++
}
</script>

<!-- 视图 -->
<template>{{ count }}</template>

它是一个独立的单元,由以下几个部分组成:

  • 状态:驱动整个应用的数据源;

  • 视图:对状态的一种声明式映射;

  • 交互:状态根据用户在视图中的输入而作出相应变更的可能方式。

下面是“单向数据流”这一概念的简单图示:

然而,当我们有多个组件共享一个共同的状态时,就没有这么简单了:

  1. 多个视图可能都依赖于同一份状态。

  1. 来自不同视图的交互也可能需要更改同一份状态。

  • 对于情景 1,一个可行的办法是将共享状态“提升”到共同的祖先组件上去,再通过 props 传递下来。然而在深层次的组件树结构中这么做的话,很快就会使得代码变得繁琐冗长。这会导致另一个问题:Prop 逐级透传问题

  • 对于情景 2,我们经常发现自己会直接通过模板引用获取父/子实例,或者通过触发的事件尝试改变和同步多个状态的副本。但这些模式的健壮性都不甚理想,很容易就会导致代码难以维护。

一个更简单直接的解决方案是抽取出组件间的共享状态,放在一个全局单例中来管理。这样我们的组件树就变成了一个大的“视图”,而任何位置上的组件都可以访问其中的状态或触发动作。

参考资料:https://cn.vuejs.org/guide/scaling-up/state-management.html#what-is-state-management

2.用响应式 API 做简单状态管理

如果你有一部分状态需要在多个组件实例间共享,你可以使用 reactive() 来创建一个响应式对象,并将它导入到多个组件中:

// store.js
import { reactive } from 'vue'

export const store = reactive({
  count: 0,
  increment() {
    this.count++
  }
})
<!-- ComponentA.vue -->
<script setup>
import { store } from './store.js'
</script>

<template>
  <button @click="store.increment()">
    From A: {{ store.count }}
  </button>
</template>
<!-- ComponentB.vue -->
<script setup>
import { store } from './store.js'
</script>
<template>
  <button @click="store.increment()">
    From B: {{ store.count }}
  </button>
</template>

为了确保改变状态的逻辑像状态本身一样集中,建议在 store 上定义方法,方法的名称应该要能表达出行动的意图。

3.Vuex基础

以上是一个表示“单向数据流”理念的简单示意

  • 状态,驱动应用的数据源;

  • 视图,以声明方式将状态映射到视图;

  • 操作,响应在视图上的用户输入导致的状态变化。

当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

  • 多个视图依赖于同一状态。

  • 来自不同视图的行为需要变更同一状态。

因此,Vuex不把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为。

通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,代码将会变得更结构化且易维护。

Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。

4.Vuex核心概念

4.1 State
4.1.1 store.state

Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 ”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

vuex中的state保存状态数据使用的。在组合式api的调用方法:

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

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

    return {
      // 在 computed 函数中访问 state
      count: computed(() => store.state.count),

      // 在 computed 函数中访问 getter
      double: computed(() => store.getters.double)
    }
  }
}

const store = useStore()表示从useStore中获取store对象

然后将获取的值放入computed中,将count放入Vuex中的state中管理。

4.1.2 mapState

当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性:

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

export default {
  setup () {
    const store = useStore()
    const storeStateFns = mapState(["counter", "name", "age"]);
    let storeState = {};
    Object.keys(storeStateFns).forEach((fnkey) => {
      // storeStateFns[fnkey]拿到每一个key对应的函数
      // .bind()给fn绑定this 才能传给computed
      const fn = storeStateFns[fnkey].binds({ $store: store });
      // 将函数通过computed函数转为ref
      storeState[fnkey] = computed(fn);
    });
    return {
      ...storeState,
    }
  }
}

上面返回的storeState是一个对象,对象内容如下{counter:fn,name:fn,age:fn},对象中都是函数,可以通过Object.keys(storeState)拿到storeState中的key值。

遍历每一个函数,并通过设置函数的this执行让其指向store

storeState = {}用于保存属性的方法,最终在return中返回,作为计算属性。

在CompositionAPI里使用mapState思路就是

  1. 通过 mapState函数 拿到所传入参数的属性的函数

  1. 通过comouted函数将这些函数转化为ref类型的数据

4.1.3 封装一个hooks

在setup中使用太麻烦,代码太冗余,此时应该封装为useState.js(.ts)文件。

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

export default function(mapper){
    const store = useStore()
    const fns = mapState(mapper);
    const state = {};
    Object.keys(fns).forEach((key) => {
      const fn = fns[key].binds({ $store: store });
      state[key] = computed(fn);
    });
    return state
}

在其他组件中使用:

 import { useState } from '../hooks/useGetters'
 
  export default {
    setup() {
      const storeGetters = useState(["nameInfo", "ageInfo", "heightInfo"]),
        return {
        ...storeGetters
      }    
    }
}

使用 Vuex 并不意味着你需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。

4.2 Getter

vuex中getter的主要目的是为了数据过滤,得到自己想要的数据。Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

4.2.1 通过属性访问

Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值

const store = createStore({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos (state) {
      return state.todos.filter(todo => todo.done)
    },
    doneTodosCount (state, getters) {
        return getters.doneTodos.length
    }
  }
})

以上代码store.getters.doneTodos获得的值是:[{ id: 1, text: '...', done: true }]

以上代码store.getters.doneTodosCount 获得的值是:1

注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。

使用方法:

 <script>
 
  import { computed } from "vue"
  import { mapGetters, useStore } from 'vuex'
 
  export default {
    setup() {
      const store = useStore();
 
      const sNameInfo = computed(() => store.getters.nameInfo)
 
      return {
        sNameInfo
      }
    }
  }

使用直接在外层套上computed即可。

4.2.2 通过方法访问

可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。

getters:{// ...
    getTodoById:(state)=>(id)=>{
        return state.todos.find(todo=> todo.id === id)
    }
}
store.getters.getTodoById(2)// -> { id: 2, text: '...', done: false }
注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
4.2.3 mapGetters辅助函数

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

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

export default {
  setup () {
    const store = useStore()
    const storeGetterFns = mapGetters(["allBooksPrice"]);
    const storeGetter = {};
    Object.keys(storeGetterFns).forEach((fnkey) => {
      const fn = storeGetterFns[fnkey].binds({ $store: store });     
      storeState[fnkey] = computed(fn);
    });
    return {
      ...storeGetter,
    }
  }
}
4.2.4 封装一个hooks

方法类似于mapState的思路,结合mapGetter与appState封装

useMap.ts

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

export default function(mapper, mapFun){
    const store = useStore()
    const fns = mapFun(mapper);
    const state = {};
    Object.keys(fns).forEach((key) => {
      const fn = fns[key].binds({ $store: store });
      state[key] = computed(fn);
    });
    return state
  }
}

在其他组件中使用:

import {mapGetters, mapState} from "vuex";
import {useMap} from ".hooks"

export default{
    setup(){
        const getters = useMap(["allBooksPrice"],mapGetters);
        const state = useMap(["Price"],mapState);
        return {
            ...getters,
            ...state,
        }
    }
}
4.3 mutations

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。简而言之是是操作state的一些方法,Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

4.3.1 mutations使用
import {createStore} from "vuex"
const store = createStore({
    state(){
        return{
            counter: 1
        }
    },
    mutation:{
        increment(state){
            state.counter++
        }
    }
})

你不能直接调用一个 mutation 处理函数。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation 处理函数,你需要以相应的 type 调用 store.commit 方法:

import {useStore} from 'vuex'
export default{
    setup(){
        cosnt store = useStore()
        increment :() => store.commit("increment")
    }
}
4.3.2 提交载荷(Payload)
mutation:{
    increment(state,n){
        state.count += n
    }
}
store.commit('increment', 10)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:

mutation:{
    increment(state,payload){
        state.count += payload.amount
    }
}
store.commit('increment',{
    amount:10
})
4.3.3 Mutation常量类型

使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:

// mutation-types.ts
export const SOME_MUTATION = 'SOME_MUTATION'
// store.ts
import { createStore } from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = createStore({
  state: { ... },
  mutations: {
    // 我们可以使用 ES2015 风格的计算属性命名功能
    // 来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // 修改 state
    }
  }
})

很多时候我们mutation可以单独进行定义,此时可以新建一个文件,里面存放变量名。

// mutation-types.ts
export enum UserMutationTypes {
  SET_USER_INFO = 'SET_USER_INFO',
}
//.ts  
[UserMutationTypes.SET_USER_INFO](state: S,payload: Record<string, any>): void;
4.3.4 mapMutations辅助函数

你可以在组件中使用 store.commit("xxx")提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

export const INCREMENT = "increment"
export const DECREMENT = "decrement"
export const INCREMENT_TEN = "incrementTen"
import {mapMutations } from "vuex"
import {INCREMENT_TEN} from "./store/mutation-types"
export default{
    setup(){
        const mut = mapMutations({
            addOne:"increment",
            subOne:"decrement",
            addTen:INCREMENT_TEN,
        });
        //const mut = mapMutations(["increment","decrement",INCREMENT_TEN]) //数组格式
        return{
            ...mut
        };
    }
}
注意: mutation 必须是同步函数。因为 vue devtool会对每一个 mutations进行快照,并且记录之前的一个值和下一个值,如果是异步的函数,则无法记录。
4.4 Action
在vuex中的 actions选项中保存的是一些异步的方法。在 actions中提交 mutation,而不是直接改变状态。
4.4.1 Action的使用

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。

  • Action 可以包含任意异步操作。

const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。

我们需要调用 commit 很多次的时候,可以用到参数解构来简化代码:

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
4.4.2 分发 Action

Action 通过 store.dispatch 方法触发:

store.dispatch('increment')

正如4.3 mutations所说, mutation 具有必须同步执行的限制么,而Action 就不受约束。我们可以在 action 内部执行异步操作:

actions: {
  incrementAsync (context) {
    setTimeout(() => {
      context.commit('increment')
    }, 1000)
  }
}

此时在actions中传入的参数为contextcontext是一个和store具有相同的方法和属性。

也可以这么写,参数解构来简化代码:

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

Actions 支持同样的载荷方式和对象方式进行分发:

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

在组件中使用 store.dispatch('xxx') 分发 action:

      asyncIncrement: () => store.dispatch('asyncIncrement')
4.4.3 mapActions 辅助函数

如果一个方法或多个方法需要在多个页面和组件中使用,那么,可以使用mapActions。想要调用多少个 action 就需要调用多少次 dispatch() ,而使用 mapActions 的话只需要往 mapActions 中传入与 action 同名的函数,然后调用这些函数即可触发对应的action

<script>
import {mapActions} from "vuex"
export default{
    setup(){
        const actions = mapActions({
            incrementAction:"incrementAction",
            incrementBySelf:"incrementBySelf",
            decrementBySelf:"decrementBySelf",
        });
        return{
            ...actions,
        };
    },
};
</script>

<template>
    <div>
        <h1>{{$store.state.counter}}</h1>
        <button @click="incrementAction">+1</button>
        <button @click="incrementBySelf({count: 10})">+10</button>
        <button @click="decrementBySelf({count: 10])">-10</button>
    </div>
</template>
4.5 module

Vuex集中式存储管理应用的所有组件的状态,放在store中,当项目达到一定的规模,那么这个store就会变得十分的复杂。这时候就需要将这样一个庞大的store进行分类处理,也就是将将store分割成一个个module(模块),便于日后的修改和管理。这与我们生活中对仓库中的物品进行分类是一样的,例如将电子类产品放在a货架上,将日常生活产品放在b货架上,这样的货架就对应了一个个module。每个module拥有自己的state、mutations、actions以及getters。

4.5.1 module的基本使用
import {createStore} from "vuex"
import homeModule from "./modules/home"
import aboutModule from "./modules/about"

const store = createStore({
    state(): => ({
        return {
            counter:0,
        }
    }),
    modules:{
        home:homeModule,
        about:aboutModule
    }
})
store.state.home // -> moduleHome 的状态
store.state.about // -> moduleAbout 的状态

export default store
//homeModule.ts
export default{
    state: ()=>({
        return{
            homeCounter:0
        }
    }),
    getters:{
    
    },
    mutation:{
    
    },
    actions:{
    
    },
}
//aboutModule.ts
export default{
    state:()=> ({
        return{
            aboutCounter:0
        }
    }),
    getters:{
    
    },
    mutation:{
    
    },
    actions:{
    
    },
}
4.5.2 modules的局部状态参数

官网的例子:https://vuex.vuejs.org/zh/guide/modules.html#

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

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

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象,也就是本模块自己的state,mutation 另一个参数是调用该函数的参数(payload)。以下代码中的mutation和getter中的参数state都是muduleA自己的state(局部状态),所以可以直接通过state.count访问到count的状态。

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

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

同样,对于模块内部的 action,存在两个参数,一个是context,另一个是传入的参数payload。

第一个参数context是一个对象,其中包含了commit,dispatch,getters,rootGetters, state,rootState。

局部状态通过 context.state 暴露出来,根节点状态(也就是整个store最外层的状态)为

context.rootState。以下代码中的state.count和rootState.count分别就是moduleA自己的状态中的

count和外部store中的状态的count。

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

对于模块内部的 getter,根节点状态会作为第三个参数暴露出来,也就是在getter中引入根节点的状态,是通过getter的第三个参数来获取。

const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}
4.5.3 module的命名空间

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的。这时候会存在弊端:

  • 弊端1:不同模块中有相同命名的mutations、actions时,不同模块对同一 mutation 或 action 作出响应。

  • 弊端2:当一个项目中store分了很多模块的时候,在使用辅助函数mapState、mapGetters、mapMutations、mapActions时,很难查询,引用的state、getters、mutations、actions来自于哪个模块,不便于后期维护。

因此可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。你的模块会具有更高的封装度和复用性。

const store = createStore({
  modules: {
    account: {
      namespaced: true,

      // 模块内容(module assets)
      state: () => ({ ... }), // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
      getters: {
        isAdmin () { ... } // -> getters['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/posts/popular']
          }
        }
      }
    }
  }
})
启用了命名空间的 getter 和 action 会收到局部化的 getter,dispatch 和 commit。换言之,你在使用模块内容(module assets)时不需要在同一模块内额外添加空间名前缀。更改 namespaced 属性后不需要修改模块内的代码。

5.Vuex+ sessionStorage实现数据储存

当一个项目逻辑层多,涉及到页面间的传参的参数会很多,页面之间跳转频繁。由于项目变得越来越复杂,单单使用Vuex会出现一些刷新时参数丢失的问题,面对所有页面都可能需要使用到的,比如说用户的登录状态,下拉框值,可以将整体的传参方式改成vuex+sessionStorage。页面涉及多层面包屑,但是不想使用keep-alive时、页面之间有很多参数是相同的,需要从一个页面带到另一个页面也可以使用Vuex+ sessionStorage实现数据储存。

5.1 Vuex数据状态持久化的使用场景

1、购物车

比如你把商品加入购物车后,没有保存到后台的情况下,前端来存,就可以通过这种方式。

2、会话状态

授权登录后,token就可以用Vuex+sessionStorage来存储。

3、一些不会经常改变的数据

比如城市列表等(当前也要留下可以更新的入口,比如版本号)

5.2一个栗子:
  1. 使用this.$store.commit()将需要缓存的数据存储到Vue store

this.$store.commit('setRemark',row.remark)
  1. 在store中新建一个js文件用于接收和修改this.$store.commit()提交上来的数据

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
    // 设置默认值
    remark:''
}
const mutations = {
    setRemark(state,remark){
        state.remark = remark
        sessionStorage.setItem('remark',remark)
      },
}
const actions = {
  
}
const getters = {
     remark:(state) => sessionStorage.getItem('remark'),
}
  1. 在需要使用的界面取值

sessionStorage.getItem['remark']
  1. 更新数据

sessionStorage.setItem('remark',remark)

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

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

相关文章

最新小程序反编译详细教程,亲测可用

小程序因为触手可及、自带推广等的特点&#xff0c;自诞生以来&#xff0c;实现了很多的商业场景&#xff0c;同时取代了App的大部分市场份额。其实小程序的开发和网页开发类似&#xff0c;同样使用的是JavaScript开发的&#xff0c;属于前端&#xff0c;所以借助一些程序的帮助…

html+css唯美登录页面,代码提供(效果展示)

文章目录效果图所有代码效果图 所有代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" cont…

vue脚手架报错:“Component name “***“ should always be multi-word”解决方法

出现的问题 在我们写完脚手架运行 npm run serve 后控制台报错 页面报错 报错的原因 在为自定义组件命名的时候未按照官方代码规范进行命名&#xff0c;根据 ESLint 官方代码风格指南&#xff0c;除了根组件&#xff08;App.vue&#xff09;以外&#xff0c;其他自定义组件命名…

若依框架登录后跳转其他页面获取不同的菜单登录进入后跳转至动态路由的第一个路由

最近碰到的需求是登录进入后,先跳转至一个自己定义的页面,在这个页面选择一个系统后,进入若依的系统,根据选择的系统获取相应的菜单,进入页面后默认跳转至后端返回的动态路由的第一个路由 1.首先在登录页面login.vue做如下改动 写成你要跳转过去的页面:(这个路由如果是自己定…

蓝桥杯冲击-02约数篇(必考)

文章目录 前言 一、约数是什么 二、三大模板 1、试除法求约数个数 2、求约数个数 3、求约数之和 三、真题演练 前言 约数和质数一样在蓝桥杯考试中是在数论中考察频率较高的一种&#xff0c;在省赛考察的时候往往就是模板题&#xff0c;难度大一点会结合其他知识点考察&#x…

安装element ui

安装element ui记录 步骤 1.先在dev控制台输入npm i element-ui --save 2.出现警告 F:\vue_test\src> npm i element-ui --save npm WARN deprecated core-js2.6.12: core-js<3.23.3 is no longer maintained and not recommended for usage due to the number of is…

Vue项目实战——实现一个任务清单(学以致用,两小时带你巩固和强化Vue知识点)

Vue2.x 项目实战&#xff08;一&#xff09; 内容参考链接Vue2.x全家桶Vue2.x 全家桶参考链接Vue2.x项目&#xff08;一&#xff09;Vue2.x 实现一个任务清单Vue2.x项目&#xff08;二&#xff09;Vue2.x 实现GitHub搜索案例Vue3.x项目&#xff08;三&#xff09;Vue3.x 实现一…

Vue 高德地图(@amap/amap-jsapi-loader)的基本使用:添加标记、POI关键字搜索、路线规划...(方法一)

高德地图的基本事件与使用前言&#xff1a; 引入并初始化渲染地图1、初始化地图2、地图鼠标点击事件3、添加标记、 移除标记点4、搜索服务——POI关键字搜索 [AMap.PlaceSearch]5、驾车路线规划服务5.1 可拖拽驾车路线规划 [AMap.DragRoute]5.2 途经点 &#xff08;起点 终点 途…

在vue3+ts项目里使用query和params传参

一 query 传参 &#xff08;类似get请求&#xff09; query 传参方式① 传递方组件 home.vue <template><div classc><p>query传参</p><el-button type"success" click"toList"> to list</el-button> </div>…

LayUI框架的使用步骤实现登录页面

目录 一、LayUI的简介 二、下载安装 三、引入并且测试 四、自定义模块 四、利用LayUI实现一个登录页面 一、LayUI的简介 1.1 什么是LayUI&#xff1f; Layui&#xff08;谐音&#xff1a;类 UI) 是一套开源的 Web UI 解决方案&#xff1b; 由国人开发&#xff08;作者贤心…

Python人脸识别

#头文件&#xff1a;import cv2 as cvimport numpy as npimport osfrom PIL import Imageimport xlsxwriterimport psutilimport time#人脸录入def get_image_name(name):name_map {f.split(.)[1]:int(f.split(.)[0]) for f in os.listdir("./picture")}if not name…

宇宙最强-GPT-4 横空出世:最先进、更安全、更有用

文章目录前言一、准确性提升1.创造力2.视觉输入3.更长的上下文二、相比于ChatGPT有哪些提升1.GPT-4 的高级推理能力超越了 ChatGPT2.GPT-4 在多种测试考试中均优于 ChatGPT。三、研究团队在GPT-4模型都做了哪些改善1.遵循 GPT、GPT-2 和 GPT-3 的研究路径2.我们花了 6 个月的时…

2022年Web前端开发流程和学习路线(详尽版)

前言 前端侧重于人机交互和用户体验&#xff0c;后端侧重于业务逻辑和大规模数据处理。理论上&#xff0c;面向用户的产品里&#xff0c;所有问题&#xff08;包括产品、设计、后端、甚至看不见的问题&#xff09;的表现形式&#xff0c;都会暴露在前端&#xff0c;而只有部分…

JS防抖和节流

前言 在进行窗口的操作或者输入框操作时&#xff0c;如果事件处理函数用的频率无限制&#xff0c;会加重浏览器和服务器的负担&#xff0c;此时我们就可以用防抖&#xff08;debounce&#xff09;和节流&#xff08;throttle&#xff09;的方式来减少调用频率&#xff0c;同时…

简析强制缓存和协商缓存

零、目录 背景介绍 http 缓存机制 使用小结 一、 背景介绍 浏览器和服务器进行交互的过程&#xff0c; 时间开销的瓶颈往往出现在数据的传输的过程之中。 这个场景类似介于 A城 到 B城 之间只有一座 “通道” &#xff0c; 每次想从A城 到 B城 &#xff0c;必须按照人数交付高…

Maven使用教程(IDEA版)

目录 一、Maven简介 1.1 在项目中如何导入jar包&#xff1f; 1.2 传统导入jar包的方式存在什么问题&#xff1f; 1.3 项目生命周期 1.4 Maven简介 二、Maven安装及配置 2.1 Maven下载 2.2 Maven安装 2.3 配置环境变量 三、Maven的项目结构 3.1 Maven的项目结构 3.2…

【CSS】CSS 特性 ③ ( CSS 优先级 | 优先级引入 | 选择器基本权重 )

文章目录一、CSS 优先级1、优先级引入2、选择器基本权重3、完整代码示例一、CSS 优先级 1、优先级引入 定义 CSS 样式时 , 可能出现 多个 类型相同的 规则 定义在 同一个元素上 , 如果 CSS 选择器 相同 , 执行 CSS 层叠性 , 根据 就近原则 选择执行的样式 , 如 : 出现两个 div…

VueX使用

vuex基本概念 vuex官方文档 vuex是vue的状态管理工具&#xff0c;状态即数据。 状态管理就是集中管理vue中 通用的 一些数据 注意&#xff08;官方原文&#xff09;&#xff1a; 不是所有的场景都适用于vuex&#xff0c;只有在必要的时候才使用vuex 使用了vuex之后&#xf…

手机解锁方法:8个顶级的 Android 手机解锁软件

一般来说&#xff0c;太简单的密码是不安全的&#xff0c;所以我们设置一个安全的密码&#xff0c;可能会稍微复杂一点。然而&#xff0c;我们可能经常会忘记复杂的密码并锁定我们的 Android 智能手机。 8个顶级的 Android 手机解锁软件 如果您遇到过这种情况并且正在寻找一种…

【vue2】vue全家桶介绍,学习vue必备

​ &#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;vue全家桶介绍&#xff0c;学习vue必备&#xff01;&#xff01;&#xff01; 【前言…