redux与vuex异同以及使用

news2025/1/18 16:58:58

一. 概述

ReactVue是我们熟悉的两大前端主流框架,来自官方的解释,Vue是一套用于构建用户界面的渐进式框架,React是一个用于构建用户界面的JavaScript库,两个框架都使用各自的语法,专注于用户UI界面的构建.那我们会有疑问,这两个框架都专注于UI界面的构建,但是随着JavaScript单页应用开发日趋复杂,我们如何进行更多数据的管理呢?比如网络请求的数据、缓存数据、本地生成尚未持久化到服务器的数据,UI状态数据,激活的路由,被选中的标签等等. 基于上面的疑问,两个框架都有各自的解决方案:React-ReduxVuex.

1. Redux 和 Vuex区别

先看Vuex作者尤雨溪的回答:

Vuex 其实是一个针对 Vue 特化的 Flux,主要是为了配合 Vue 本身的响应式机制。当然吸取了一些 Redux 的特点,比如单状态树和便于测试和热重载的 API,但是也选择性的放弃了一些在 Vue 的场景下并不契合的特性,比如强制的 immutability(在保证了每一次状态变化都能追踪的情况下强制的 immutability 带来的收益就很有限了)、为了同构而设计得较为繁琐的 API、必须依赖第三方库才能相对高效率地获得状态树的局部状态等等(相比之下 Vuex 直接用 Vue 本身的计算属性就可以)所以 Vue + Vuex 会更简洁,也不需要考虑性能问题,代价就是 Vuex 只能和 Vue 配合。Vue + Redux 也不是不可以,但是 Redux 作为一个泛用的实现和 Vue 的契合度肯定不如 Vuex。

Vuex改进了Redux中的Action和Reducer函数,以mutations变化函数取代Reducer,无需switch,只需在对应的mutation函数里改变state值即可
Vuex由于Vue自动重新渲染的特性,无需订阅重新渲染函数,只要生成新的State即可
Vuex数据流的顺序是∶View调用store.commit提交对应的请求到Store中对应的mutation函数->store改变(vue检测到数据变化自动渲染)
通俗点理解就是,vuex 弱化 dispatch,通过commit进行 store状态的一次更变;取消了action概念,不必传入特定的 action形式进行指定变更;弱化reducer,基于commit参数直接对数据进行转变,使得框架更加简易;

2. 共同思想

  • 单—的数据源
  • 变化可以预测
  • 本质上∶ redux与vuex都是对mvvm思想的服务,将数据从视图中抽离的一种方案。

vuex 和 redux 都是状态管理库,用于单独管理状态的。其中,redux是一个范用的库,可以单独使用。而vuex是专门用来配合vue使用的。他们都应用了flux架构的思想,但是在接口的提供上稍有不同。

3.核心概念对比

Redux 的核心概念

  • action (同步action ,或借助 中间件 实现异步操作,action 不会改变 store,只是描述了怎么改变store)| mutation(用于同步操作) 、action(可用于异步操作,提交 mutation)
  • reducer(纯函数,根据 action 和旧的 store 计算出新的 store)
  • store(单一数据源)

Vuex 的核心概念

  • mutation(用于同步操作) 、action(可用于异步操作,提交 mutation)
  • mutation里面直接修改 state
  • state(单一数据源)

4. 使用原则:

Redux 的三大原则:

  1. 单一数据源(一个Redux应用只有一个store),也是单向的数据流
  2. state只读(唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象)
  3. 使用纯函数(reducer)来修改state。

redux的流程:

view——>action——>store——>reducer(返回)——>store——view

Vuex 的三大原则:

  1. 应用层级的状态应该集中到单个 store 对象中。
  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  3. 异步逻辑都应该封装到 action 里面。

vue的流程:

​ vueComponent——>(dispatch)action——>(commit)——>mutations——>(mutate)state——>(render)vueComponent

5. 处理异步操作

Redux 的中间件机制,利用 redux-thunk ,redux-thunk可以dispatch函数,这个函数用于生成action,所以在这个函数里我们可以进行异步操作,等异步的结果出来后再放在action里面,将这个action用dispatch分发出去,而这个函数被叫做 “action creator”,可以将异步逻辑放在 action creator 里面,给 action creator 传入 dispatch 作为参数,于是就可以 dispatch action,Redux 并没有创造单独的概念出来专门用于异步逻辑,它是利用了 Redux 自己实现的中间件机制,中间件从 dispatch 一个异步 action 到 action 到达 reducer 之间处理 action,在这期间通过异步操作得到的结果可以放到 action 里面再通过 dispatch 分发到 reducer,以前 dispatch 一个 action 之后,这个 action 回立即到达 reducer ,所以是同步 action,现在在 action creator 里面,可以等待异步操作结果再生成 action 分发,所以叫做异步 action

而 Vuex 是用 mutation 来对应 Redux 的 action,另外 Vuex 又创造了一个 action 来提交 mutation 并通过异步提交 mutation 来实现异步操作结果能够修改 state.

二.使用

1.Redux

使用react-redux之前我们先来了解一下ReduxRedux是 JavaScript 状态容器,提供可预测化的状态管理,ReduxFlux演变而来,当然除了和React一起用外,还支持其它界面库,不过我们这里主要介绍它配合React进行使用.先来了解下它的几个核心概念:

(1) 核心概念

  • State: 所谓的state就是React组件所依赖的状态对象。你可以在里面定义任何组件所依赖的状态。比如一个简单的todo应用的state可能是这样
{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}
  • Action: action就是一个普通JavaScript对象,用来描述发生了什么.比如
{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

你可以把action理解为一个描述发生了什么的指示器。在实际应用中,我们会dispatch(action),通过派发action来达到修改state的目的。这样做的好处是可以清晰地知道应用中到底发生了什么。

  • Reducer:reducer的作用是用来初始化整个Store,并且串起stateaction, 它是一个接收stateaction并返回新state的函数.我们可以通过区分不同的action类型,来处理并返回不同的state.
const StoreAction = (state = defaultState,action) => {
    switch (action.type) {
        case HOME_ACTION_UPDATE_STATE:
            return {...state,...action.data};
        case ADD_ARTICLELIST_STATE:
            let newState = JSON.parse(JSON.stringify(state));/// 深拷贝
            newState.articleList = newState.articleList.concat(action.data);
            return newState;
        default:
            return state;
    }
}

(2) 使用原则

使用Redux进行数据管理时有三个原则需要注意

  • 单一数据源
    整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一一个store中。
  • State 是只读的
    唯一改变state的方法就是触发actionaction是一个用于描述已发生事件的普通对象。
  • 使用纯函数来执行修改
    我们通过reducer接收先前的stateaction,并返回新的state, Reducer必须是一个纯函数,所谓的纯函数就是一个函数的返回结果只依赖于它的参数,并且在执行过程中没有副作用。

(3)React Redux

react-reduxRedux官方提供的React绑定库.他的使用也遵循上面的redux原则。

  • 安装
npm install --save react-redux
  • 流程

    在这里插入图片描述

    image.png

通过上面的流程图可以很清晰的明确Redux的使用:

React组件首先调用ActionCreators里事先定义好的方法,得到一个actoion,通过dispatch(action)达到派发actionReducer的目的。Reducer通过接受的不同的action来对state数据进行处理,处理完成后,返回一个新的state,state变化后React组件进行重新渲染。

  • 使用

    • 入口文件index.js

      import React from 'react'
      import { render } from 'react-dom'
      import { Provider } from 'react-redux'
      import { createStore } from 'redux'
      import todoApp from './reducers'
      import App from './components/App'
      
      let store = createStore(todoApp)
      
      render(
        <Provider store={store}>
          <App />
        </Provider>,
        document.getElementById('root')
      )
      
  • 创建store/reducer.js

    import { ADD_TODO_LIST_VALUE } from "./actionTypes";
    
    /// 初始化数据
    const defaultState = {
        todos: [{
            text: 'Eat food',
            completed: true
          }, {
            text: 'Exercise',
            completed: false
          }],
          visibilityFilter: true,
    }
    /// Reducer 可以接受state,但是不能修改State !
    export default (state = defaultState , action) => {
      switch (action.type) {
          case ADD_TODO_LIST_VALUE:
            const newState = JSON.parse(JSON.stringify(state));///将原来的state 做一次深拷贝
            newState.todos.push(action.value);
            return newState;
          default:
            return state;
      }
    }
    
  • 根据reducer创建store/index.js,

    import { createStore,compose,applyMiddleware } from 'redux';
    import reducer from './reducer';
    
    const store = createStore(reducer);
    export default store;
    
  • 创建actionCreatorsstore/actionCreators.js

    import { ADD_TODO_LIST_VALUE } from "./actionTypes"
    
    export const addItemListAction = (value) => ({
          type:ADD_TODO_LIST_VALUE,
          value
    })
    
  • 创建actionTypes专门用来存储action的type值

    export const ADD_TODO_LIST_VALUE = 'add_todo_list_value';
    
  • React组件中使用

    import React, { Component } from 'react';
    import { addItemListAction } from '../pages/home/store/actionCreators';
    import {connect} from 'react-redux';
    
    class Customtodolist extends Component {
        render() {
            return (
                <div className='todo-list' onClick={()=>{this.props.addListItem()}}>
                  <ul>
                      { 
                        this.props.todos.map((item,index) => 
                          <li key={index}>{index}:{item}</li>
                        )
                      }
                    </ul>
                </div>
            );
        }
    }
    const mapStateToProps = (state) => {
        return {
            todos: state.todos
        }
    }
    
    const mapDispatchToProps = (dispatch) => {
        return {
            addListItem: () => {
                const item = {text: 'Eat food',completed: true}
                const actionCreator = addItemListAction(item);
                dispatch(actionCreator);
            }
        }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Customtodolist);
    

    我们通过react-reduxconnect方法,将mapStateToProps与mapDispatchToProps 方法与组件链接,然后直接在类组件中通过this.props.XXX的方式进行访问Store中的state.

  • React hooks中使用

    /// hooks 中使用react-redux
    import { useSelector, useDispatch } from 'react-redux';
    const Home = (props)=> {
        // hook 获取store state 方式
        const storeCount = useSelector(state => state.home.count);
        // 获取actionCreator方法
        const dispatch = useDispatch();
      
        return (
          <div className={style['home-content']}>
              <div className='home-content-detail'>
                  StoreCount数据展示{storeCount}
                  <div>
                    {/* addStoreCount是在actionCreators中定义的方法 */}
                    <button onClick={()=> {dispatch(addStoreCount(0))}}>点击storeCount+1</button>
                  </div>
              </div>
          </div>
      )
    }
    
  • redux-thunk的使用

    redux-thunkredux的中间件.他的主要作用是可以使用异步派发action。例如我们要进行网络请求,那么可以在actionCreators里面异步派发action.

    安装与使用

    npm install --save redux-thunk
    

    (1).在store/index.js 中添加引入

    import thunk from "redux-thunk";/// redux-thunk 中间件 需要引入的
    

    (2). 使用thunk初始化store

    /// 下面的代码是固定写法 /// redux-thunk 中间件 需要引入的
    const composeEnhancers =
      typeof window === 'object' &&
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
        }) : compose;
    
    /// 中间件都需要用这个方法
    const enhancer = composeEnhancers(
        applyMiddleware(thunk),/// redux-thunk 中间件 需要引入的
    );
    /// 创建
    const store = createStore(
        reducer,
        enhancer//使用Redux-thunk 中间件
    );
    

    (3).在actionCreater.js 中添加异步派发函数,注意:在获取到异步处理的结果后,我们仍然需要调用actionCreater.js中的其他创建action方法,来对其进行dispatch.

    export const initListAction = (data) => ({
        type:INIT_LIST_ACTION,
        data
    })
    
    /// 将异步请求 放在 Action 中执行
    export const getToList = () => {
       /// 这里返回一个函数,能获取到 dispatch 方法 这就是 redux-thunk 的作用,可以返回一个函数
        return (dispatch) => {
            axios.get('/api/todolist').then((res) => {
                // alert(res.data);
                const data = res.data;
                const action = initListAction(data);
                dispatch(action);
            }).catch((error)=>{
                console.log('网络请求错误了---thunk----》');
            })
        }
    }
    
  • reducer的拆分与合并

    随着项目功能模块越来越多,如果只有一个reducer来维护state,会使其变动越来越大,从而导致难以维护。combineReducer应运而生, 它将根reducer分拆成多个 reducer,拆分之后的 reducer 都是相同的结构(state, action),并且每个函数独立负责管理该特定切片 state 的更新。多个拆分之后的reducer可以响应一个 action,在需要的情况下独立的更新他们自己的切片 state,最后组合成新的 state。

    使用

    import { combineReducers } from 'redux';/// 将小的Reducer 合并成大的reducers
    /// 需要拆分 
    import headerReducer from '../common/header/store/reducer'
    import mainReducer from './mainReducer';
    import {reducer as homeReducer} from '../pages/home/store';
    import {reducer as loginReducer} from '../pages/login/store';
    
    /// 进行 reducer的合并
    const reducer = combineReducers({
        header:headerReducer,
        main:mainReducer,
        login:loginReducer,
        home:homeReducer,
    })
    
    export default reducer;
    

    react组件中使用,要加上reducer名称,例如我们在Home组件中这样获取其state

    const mapStateToProps = (state, ownProps) => {
        return {
            showScroll: state.home.showScroll,//state后面添加reducer名称
        }
    }
    

2.Vuex

Vuex是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。它主要用来解决多个组件共享状态的问题。

在这里插入图片描述

image.png

VuexRedux的数据管理模式很相似,如果理解Redux,那么Vuex也很容易理解了,只不过Vuex 是专门为 Vue.js 设计的状态管理库,使用起来要更加方便。

(1) 核心概念

  • State: 就是组件所依赖的状态对象。我们可以在里面定义我们组件所依赖的数据。可以在Vue组件中通过this.$store.state.XXX获取state里面的数据.

  • Getter:从 store 中的 state 中派生出一些状态,可以把他理解为是store的计算属性.

    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)
        }
      }
    })
    

    例如我们定义了上面的store,在Vue组件中通过store.getters.doneTodos访问它的getter.

  • Mutation:更改 Vuex 的 store 中状态的唯一方法是提交 mutation,我们通过在mutation中定义方法来改变state里面的数据。

    const store = createStore({
      state: {
        count: 1
      },
      mutations: {
        increment (state) {
          // 变更状态
          state.count++
        }
      }
    })
    

    在Vue组件中,我们通过store.commit('increment'),来提交。需要注意的是,Mutation 必须是同步函数。在实际使用中我们一般使用常量替代 Mutation 事件类型。例如:

    export const INCREMENT_MUTATION = 'INCREMENT_MUTATION'
    
    const store = createStore({
      state: {
        count: 1
      },
      mutations: {
        // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
        [INCREMENT_MUTATION] (state) {
          // 变更状态
          state.count++
        }
      }
    })
    
  • Action: Action 类似于 Mutation,不同在于:

    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作。
    const store = createStore({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      },
      actions: {
        incrementAsync ({ commit }) {
        setTimeout(() => {
          commit('increment')
        }, 1000)
       }
      }
    })
    

    在组件中我们通过store.dispatch('incrementAsync')触发action。

  • Module: 当我们的应用较大时,为了避免所有状态会集中到一个比较大的对象中,Vuex 允许我们将 store 分割成模块(module),你可以把它理解为Redux中的combineReducer的作用.

    const moduleA = {
    state: () => ({ ... }),
    mutations: { ... },
    actions: { ... },
    getters: { ... }
    }
    const moduleB = {
      state: () => ({ ... }),
      mutations: { ... },
      actions: { ... }
    }
    
    const store = createStore({
      modules: {
        a: moduleA,
        b: moduleB
      }
    })
    

在Vue组件中我们使用store.state.a, store.state.b来分别获取两个模块的状态.

(2) 使用

  • 安装

    npm install vuex@next --save
    OR 
    yarn add vuex@next --save
    
  • main.js中挂载store

    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    import store from './store';
    
    createApp(App).use(store).use(router).mount('#app');
    
  • 创建store/index.js

    import { createStore } from 'vuex';
    import { ADD_ITEM_LIST, REDUCE_ITEM_LIST, CHANGE_ITEM_LIST_ASYNC } from './constants';
    
    export default createStore({
      state: {
        itemList: [
          { text: 'Learn JavaScript', done: true },
          { text: 'Learn Vue', done: false },
          { text: 'Build something awesome', done: false },
        ],
      },
      getters: {
        doneItemList: (state) => state.itemList.filter((todo) => todo.done),
      },
      mutations: {
        // 使用ES2015风格的计算属性命名功能 来使用一个常量作为函数名
        [ADD_ITEM_LIST](state, item) {
          console.log('增加数据', item);
          state.itemList.push(item);
        },
        [REDUCE_ITEM_LIST](state) {
          console.log('减少数据');
          state.itemList.pop();
        },
      },
      actions: {
        [CHANGE_ITEM_LIST_ASYNC]({ commit, state }, todoItem) {
          /// 模拟网络请求
          setTimeout(() => {
            commit(ADD_ITEM_LIST, todoItem);
            console.log('state===', state);
          }, 1000);
        },
      },
      modules: {
      },
    });
    

注意我们这里仍然使用常量来作actionsmutations的方法名,使用时候要加上[].

  • 在选项式API中使用

    <template>
      <div class="about">
        <div>{{counter}}</div>
        <button @click="handleClick">按钮</button>
        <div>     
         <div>
           <TodoItem :itemList="$store.state.itemList"/>
         </div>
          <div>
            完成的Todo
           <TodoItem :itemList="$store.getters.doneItemList"/>
         </div>
         <div class="btn-content">
           <button @click="addClick">增加Item</button>
           <button @click="reduceClick">减少Item</button>
           <button @click="changeClickAsync">调用Action</button>
         </div>
        </div>
      </div>
    </template>
    
    <script>
    import TodoItem from '../components/TodoItem.vue';
    import {
      ADD_ITEM_LIST, REDUCE_ITEM_LIST, CHANGE_ITEM_LIST_ASYNC,
    } from '../store/constants';
    
    export default {
      name: 'About',
      components: {
        TodoItem,
      },
      data() {
        return {
          counter: 0,
        };
      },
      computed: {
        todos() {
          return this.$store.getters.doneItemList;
        },
      },
      methods: {
        handleClick() {
          console.log('handleClick--->');
          this.counter += 1;
        },
        addClick() {
          const item = { text: 'add_item_list success!', done: true };
          /// 提交mutations
          this.$store.commit(ADD_ITEM_LIST, item);
        },
        reduceClick() {
          this.$store.commit(REDUCE_ITEM_LIST);
        },
        changeClickAsync() 
          const item = { text: 'async_add_item_list success!', done: true };
          ///派发actions
          this.$store.dispatch(CHANGE_ITEM_LIST_ASYNC, item);
        },
      },
    };
    </script>
    
  • 在组合式API中使用

    在组合式API中通过调用 useStore 函数,来在 setup 钩子函数中访问 store。这与在组件中使用选项式 API 访问 this.$store 是等效的.

    import { useStore } from 'vuex'
    import { computed } from 'vue'
    
    export default {
      setup () {
        const store = useStore()
        return {
          // 在 computed 函数中访问 state
          count: computed(() => store.state.count),
    
          // 在 computed 函数中访问 getter
          double: computed(() => store.getters.double)
          
           // 使用 mutation
          increment: () => store.commit('increment'),
    
          // 使用 action
          asyncIncrement: () => store.dispatch('asyncIncrement')
        }
      }
    }
    

三. 总结

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

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

相关文章

PAG动画研究

阅读文章大约需要6分钟 一、什么是PAG 官方定义&#xff1a;PAG&#xff08;Portable Animated Graphics&#xff09; 是一套完整的动画工作流。提供从AE导出插件&#xff0c;到桌面预览工具PAGViewer&#xff0c;再到各端的跨平台渲染 SDK。 二、PAG的优势 1、动画文件小&a…

[附源码]Python计算机毕业设计工程车辆动力电池管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

【DevOps实战系列】第四章:详解Jenkins搭建及使用

个人亲自录制全套DevOps系列实战教程 &#xff1a;手把手教你玩转DevOps全栈技术 Jenkins概述 根据jenkins官网对自己的描述&#xff0c;它是一个可集成有1800插件的自动化服务&#xff0c; 提供构建、部署和自动化的工程&#xff0c;可以说是opsdev的大总管&#xff0c;将开发…

zabbix部署+报警模块+图形模块+管理模块+添加监控模板

目录 安装zabbix 部署zabbix 配置zabbix 1. 修改语言 2. 监控linux端 3. 修改中文乱码 报警功能 报警音报警 邮件报警 脚本报警 邮件通知内容 图形模块 创建图形 创建聚合图形 percona mysql模板 nginx模板 克隆主机 网络发现 自动注册 主被动模式 &#x1f341;如果对你有帮助…

Vue + Element-ui实现后台管理系统---项目搭建 + ⾸⻚布局实现

目录&#xff1a;导读 项目搭建 ⾸⻚布局实现 一、项目搭建 1、环境搭建 2、项目初期搭建 二、Main.vue 三、左侧栏部分(CommonAside.vue) 四、header部分(CommonHeader.vue) 五、Home.vue 写在最后 项目搭建 ⾸⻚布局实现 这篇主要讲解 项目搭建 后台⾸⻚布局实现…

Oracle项目管理之设施与资产管理Facilities and Asset(中文)

目录 维护管理 独立或集成 设施状况评估 空间管理 租赁管理 交易管理 资产组合管理 投资组合管理能力 可持续性和能源管理 单一综合设施和资产生命周期管理 Oracle Primavera Unifier 设施与资产管理是一个功能强大且易于使用的解决方案&#xff0c;用于管理您的财产…

第九章服务器内部转发和客户端重定向

文章目录为什么需要转发和重定向服务器内部转发客户端重定向重定向的相关的状态码对比转发和重定向的应用场景为什么需要转发和重定向 发一个请求给Servlet&#xff0c;接力棒就传递到了Servlet手中。而绝大部分情况下&#xff0c;Servlet不能独自完成一切&#xff0c;需要把接…

云原生之使用docker部署qbittorrent

云原生之使用docker部署qbittorrent一、qbittorrent介绍二、检查本地docker状态三、下载qbittorrent四、部署qbittorrent1.创建数据目录2.创建qbittorrent容器3.查看qbittorrent容器状态五、访问qbittorrent1.进入qbittorrent 登录页2.进入qbittorrent 首页六、qbittorrent的基…

在 Vue 中,使用 $attrs 构建高级组件

我们来看下 Vue3 中的 $attrs 属性。首先&#xff0c;我们会介绍它的用途以及它的实现与 Vue2 有哪些不两同点&#xff0c;并通过事例来加深对它的理解。 真正理解了 $attrs 属性有助于我们构建易于使用和可扩展的高级组件 什么是 $attrs 对 $attrs 定义&#xff0c; Vue2 与…

百亿诈骗案频出,欧科云链用“技术责任”拓宽Web3安全边界

2022年12月1日&#xff0c;《中华人民共和国反电信网络诈骗法》正式实施&#xff0c;中国正式迈入“全民反诈时代”。据CNNIC和智研咨询统计显示&#xff0c;截至2021年12月&#xff0c;国内网民遭遇网络诈骗比例为16.6%&#xff0c;数千万人深受网络诈骗的危害。 以新兴技术区…

第05讲:Security之基于注解的用户授权

使用注解进行用户授权只需要两个步骤&#xff1a; 在SecurityConfig配置类上添加开启用户授权的注解EnableGlobalMethodSecurity(securedEnabled true)在需要被授权的Controller上添加授权的注解 一、新建项目&#xff0c;并进项相关配置 参考&#xff1a;第04讲&#xff1…

重大变化:Documents for Excel (GcExcel) 6.0-Crack

GrapeCity Documents for Excel&#xff0c;Java 版 在 Java 应用程序中以编程方式轻松生成、加载、修改和转换 Excel .xlsx 电子表格。GrapeCity Documents for Excel (GcExcel) 是一个跨平台的高速、占用空间小的电子表格 API 库&#xff0c;不需要依赖 Excel。使用此电子表…

《山本耀司》- 我不烦你,请你也不要来烦我

《山本耀司: 我投下一枚炸弹》 关于作者 山本耀司是时尚界日本新浪潮的新掌门 人&#xff0c;与川久保玲、三宅一生并称日本时尚 界的三驾马车&#xff0c;同时也是20世纪80年代闯 入巴黎时装舞台的先锋派人物之一。他的设计以黑色为主色调&#xff0c;奔放且宽松&#xff0c;…

Mac环境编译安装tesseract-4.1.1

Mojave 编译安装 tesseract-4.1.1 前言 顺便学习下Python&#xff0c;尝试使用Python3安装tesseract进行文字识别&#xff0c;结果踩了好深一个坑&#xff0c;特此记念…… 好多坑&#xff0c;好多坑…… 参考彭世瑜的这一篇&#xff1a;https://blog.csdn.net/mouday/arti…

一起从零开始学VUE(15)初识VUE3

创建Vue3.0工程 使用vue cli 需要保证vue的版本在4.5以上使用vite创建——新一代前端构建工具 开发环境中&#xff0c;无需打包操作&#xff0c;可快速的冷启动轻量快速的热重载HMR真正的按需编译&#xff0c;不再等待整个应用编译完成 步骤 创建工程 npm init vite-app <…

docker安装达梦数据库最佳实践

达蒙数据库 数据库安装部署 下载地址&#xff1a;产品下载 | 达梦数据库 安装博客地址&#xff1a;安装前准备 | 达梦技术文档 到官网docker部署那一章节&#xff0c;下载镜像tar包&#xff0c;上传到服务器上后&#xff0c;运行下面的命令 docker安装启动脚本&#xff1a;…

window10录屏怎么录?看完这篇文章,快速掌握

Windows系统的电脑用户有不少&#xff0c;有时我们需要录制屏幕与朋友分享电脑屏幕上的内容&#xff0c;windows10录屏怎么录&#xff1f;其实windows10录屏的操作很简单&#xff0c;今天小编就和大家分享详细的windows10录屏的操作步骤。 一、使用QQ对windows10录屏 很多小伙…

java计算机毕业设计基于安卓Android的跨校区班车乘车预约系统APP

项目介绍 网络的广泛应用给生活带来了十分的便利。所以把班车乘车预约与现在网络相结合,利用java 技术建设班车乘车预约APP,实现谷惠农产品线上销售的信息化。则对于进一步提高乘车发展,班车乘车预约经验能起到不少的促进作用。 班车乘车预约APP能够通过互联网得到广泛的、全面…

SSM整合xml方式(精简版)

注&#xff1a;本次只介绍ssm整合的核心部分&#xff0c;不重要的部分进行了省略 1、maven核心依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2…

BEPUphysicsint碰撞事件详解

上一节我们給大家介绍了BEPUphysicsint的基本使用,在游戏开发中我们经常要使用物理引擎的事件&#xff0c;所以本节我们详细的讲解BEPUphysicsint 的物理事件。此物理引擎会产生了碰撞事件与非碰撞事件&#xff0c;碰撞事件大家好理解&#xff0c;非碰撞事件例如: 物理Entity的…