vue3与vue2的基础对比总结

vue2与vue3的区别简介

        1.api的区别

                vue2 逻辑比较分散 可读性差 可维护性差 api被默认全部引入( Tree shaking)                                    vue3 逻辑分明 可维护性 高 api按需引入(  Tree shaking没用到就不会给你打包减少体积)

        2.双向绑定原理的区别

        vue2基于Object.defineProperty():

                原理:备份数据再循环遍历数据。

                缺点:监听不到数组length的改变和对象动态属性的改变和删除属性(在creacted未定义之后的改变,使用$set)

        vue3基于Proxy

let proxyObj = new Proxy(obj,{
        get : function (target,prop) {
            return prop in target ? target[prop] : 0
        },
        set : function (target,prop,value) {
            target[prop] = 888;
        }

        3.dom更新的区别

                Vue2中,每次更新diff,都是全量对比

                Vue3则只对比带有标记的( patch flag(补丁标记)),这样大大减少了非动态内容的对比消耗

        4.vue3 api的写法

                Setup 函数式编程 也叫vue Hook

               例如 ref  reactive watch computed toRefs toRaws

        5.Fragment

                vue2中只能有一个根节点

                vue3中允许template的多个根节点,且支持render  jsx的写法,类似react

vue3的具体使用

        创建项目

                1. vite脚手架

#使用 NPM:
npm init vite@latest

#yarn 【推荐】
yarn create vite

#pnpm
pnpm create vite

        ......配置项目名字等....

cd vue3-demo
yarn
code . //项目自动在vscode中打开
yarn dev

      显示ip的运行地址,默认不显示ip

                重新启动项目后

         2.create-vue脚手架

        快捷安装vue3+vite的工具,还有中文选择需要的模块,不再手动安装vite

        使用条件:

               1. 已安装 18.3 或更高版本的 Node.js :node -v

               2. 安装vue3最新版本:

                        npm list vue (查看vue版本)

                        npm create vue@latest

        vscode 推荐插件

  • 禁用 vetur插件(vue2使用)
  • vscode 插件推荐 Vue Language Features (Volar) (已经停止维护:vue - official替代)

  • vue3-snippets-for-vscode

        项目的结构搭建

         安装插件后的快捷键快速创建自定义组件的模板结构
  • v3 -------> v3p(volar)
  •  vinit(vue3-snippets-for-vscoder)

        scrips标签的两种写法

        代码的编写

             ref 数据响应

                用于基本数据的拦截,或者获取dom连接

  • 基本数据类型绑定
    • 创建 RefImpl 响应式 Proxy 对象 ref 内部: 通过给 value 属性添加 getter/setter 来实现对数据的劫持
    • 定义数据之后,模板里面直接使用值
    • 修改数据 用.value 属性修改
  • 响应式状态需要明确使用响应式 APIs 来创建。和从 setup() 函数中返回值一样,ref 值在模板中使用的时候会自动解包
  • <template>
        {{变量名}}
        <button @click='change'>点击我</button>
        
        //注意:事件内容写在html中时,变量名已经是一个字符串,因此无.value!!!!
         <button @click='变量名=新值'>点击我</button>
         
    </template>
    
    
    
    #0、引入ref 函数(快捷键入:ref)
    import { ref } from 'vue'
    
    #1、创建响应式数据
    const 变量名 = ref(初始值)
    
    #2、修改响应式数据   注意别修改原数据
    const change = ()=> {
      变量名.value = 修改之后的值
    }
    function reverseMessage() {
      // 通过其 .value 属性
      // 访问/修改一个 ref 的值。
      message.value = message.value.split('').reverse().join('')
    }
    #3、创建dom 绑定必须变量名 相同
    const 变量名 = ref(null)

    更改变量的值

  • //普通值:a的值不是响应式的,所有更改后不会更新视图
    const changeA=()=>{
        a = 'AAAAA'
        console.log(' a : ',  a );
        
    }
    //ref拦截的值:.value
    const changeB = ()=>{
        //只有ref创建对象中的value值是被拦截的,不是整个对象
        /*注意我们不需要在模板中写 .value,
        因为在模板中 ref 会自动“解包”。*/
        b.value = 'BBBBBBB'
    }
    

    获取dom

  •        reactive 数据响应

  • 作用: 引用类型的数据响应定义

    • 作用: 定义多个数据的响应式
    • const proxy = reactive(obj): 接收一个普通对象然后返回该普通对象的响应式代理器对象
    • 响应式转换是“深层的”:会影响对象内部所有嵌套的属性
    • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的
    • <template>
          {{state.属性1}}
      </template>
      
      <script setup>
      #引入reactive 函数
      import { reactive } from 'vue'
      
      
      #创建响应式数据:通过proxy代理进行数据的劫持
      const state = reactive({
          属性1:值1,
      })
      
      #修改响应式数据 
      const state= ()=>{
          state.name = '小狼'
          state.k1.k2 = 999
      } 
      </script>

      toRef

      作用:将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref 。

      即,把对象中的属性解构出来,不用再对象.属性名

    •  <div>解构对象属性:{{age}}</div>
         
      //0、引入toRef      
      import { reactive, toRef } from 'vue';
      
      const obj = reactive({
          name:'reactive',
          age:'12',
          son:{name:'vue'}
      })
      
      // 2、解构对象属性,直接使用属性名
      const age = toRef(obj,'age')
      
      console.log('age: ', age);
      console.log('obj: ', obj.age);
      
      // 3、更改值
      function changeToRef(){
          //也会更改其他使用age的值
          age.value = 222    
      }

      refs

    • 批量解构出对象的属性

    • //引入refs
      import {toRefs } from 'vue';
      
      #创建响应式数据
        const state = reactive({
          name: '小樱',
          age: 11,
          hobs: ['唱歌', '跳舞'],
          hands: {
              left: 100
          }
      })
      
      
      
      #响应的ref数据改变会影响原代理对象
      const { name, age, hobs, hands } = toRefs(state)
      
      const change = () => {
          name.value = '小狼'
          age.value = 12
          hobs.value[0] = '洗澡澡'
          hands.value.left = 200
      }

      computed

      • 当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据

      • 与computed配置功能一致
      • 只有getter
      • 有getter和setter
      • vue2写法

      • computed:{
        	sum(){}  ----- //sum :function(){}
        }
        
        computed:{
        	sum:{ 	------//sum:{ }
        		get:()=>{},
        		set:()=>{},
        	}
        }

        vue3写法:

      • let a = ref(12)
        let b = ref(13)
        
        const sum = computed(() => {   //----sum :function(){}
        	return a.value + b.value//25
        })
        
        const reduce = computed({ //----sum : { }
        	get() {
        		return a.value - b.value
        	},
        	set() {
        		return a.value - b.value
        	},
        })

         watch

        • 与watch配置功能一致
        • 监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
        • 默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次
        • 通过配置deep为true, 来指定深度监视
        • vue2的写法:注意:watch中不能使用箭头函数

        • watch:{
          	sum(){}//----sum :function(){}
          }
          
          watch:{
          	sum/'form.newPwd':{//----sum : { }
          		hander(){},
          		deep:true
          	}
          }

          vue3

        • // 1.监听单个 基本数据
          watch(name, (va1, val2) => {
          	console.log('监听单个 基本数据', va1, val2)
          })
          
          // 2.监听单个 复合数据
          watch(obj,//()=>JSON.parse(JSON.stringify(obj))
          	(va1, val2) => {
          		console.log('参数: obj', va1, val2)
          		/*//新旧值相同,这是因为它们的引用指向同一个对象/数组
          			Proxy(Object) {age: '19', sex: '女', love: '小狗', ho: '小猫', s111: '1111', …},
          			Proxy(Object) {age: '19', sex: '女', love: '小狗', ho: '小猫', s111: '1111', …}
          			 */
          		// console.log('参数:()=>JSON.parse(JSON.stringify(obj))', va1, val2);
          		/*
          			{age: '19', sex: '女', love: '小狗', ho: '小猫', s111: '1111', …}
          			{age: '18', sex: '女', love: '小狗', ho: '小猫', s111: '1111', …}
          		 */
          
          
          	},
          )
          
          // 3.监听多个数据
          watch([name, ho], ([va1, v1], [va2, v2]) => {
          	console.log(' 监听多个数据1', va1, va2)//vvvvv vue3
          	console.log(' 监听多个数据2', v1, v2)//小猫 小猫
          
          })
          watch([name, ho], (v1, v2) => {
          	console.log(' 监听多个数据', v1, v2)
          	//(2) ['vvvvv', '小猫'](2) ['vue3', '小猫']
          })
          
          // 4.监听单个 对象属性
          watch(() => obj.age, (va1, val2) => {
          	console.log(' 监听单个 对象属性', va1, val2)
          })
          
          /*5.watchEffect:
          - 不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据
          - 默认初始时就会执行第一次, 从而可以收集需要监视的数据
          - 监视数据发生变化时回调 */
          watchEffect(() => {
          	console.log('watchEffect观察 :>> ', name.value);
          	console.log('watchEffect观察 :>> ', obj.age);
          })
          

          组件传值

        • 组件的引入与使用

          快捷引入:直接键入chil(父子组件放在同一层级)

        • <template>
              <h1>props:父传子(父组件)</h1>
              
              //2.组件的使用(组件名为两个首字母大写,使用时可以使用-隔开)
              <ChildVue></ChildVue>
              <!--另外种使用方法: <child-vue></child-vue> -->
              
          </template>
          
          <script setup>
          //1.引入组件,不用componnents注册了
          import ChildVue from "./Child.vue";
          </script>
          1.父传子
          • 父组件传值:同vue2,使用 :变量名1='变量名2'
        • <ChildItemVue :toChild="toChild"></ChildItemVue>
          <ChildItemVue :tochildReact="tochildReact"></ChildItemVue>
          
          <script setup>
          import { reactive, ref } from "vue";
          import ChildItemVue from "./ChildItem.vue";//child快捷键,同级时
          //------- 父传子的值----
          const toChild = ref('child,吃饭没得?饿不饿?')
          const tochildReact = reactive({ text: '渴了没得?喝奶茶不?' })
          </script>
          • 子组件取值:defineProps({ })//新版本不用import,已经内置,快捷键define

            • vue2写法

          • props:['toChild'],
            
            props:{
            	toChild:{
            		typeof: String,
            		default: '父组件没有传值'
            	}
            }

            vue3写法

          • defineProps({
            	// toChild: String,
            	toChild: {
            		typeof: String,
            		default: '莫得'
            	},
            	tochildReact: {
            		typeof: () => { return {} },
            		default: { text: '莫得' }
            	}
            })
                 2.子传父

                setup函数中没有this,因此没有this.$emit,需要使用defineEmits函数注册类似$emit的函数

               

                        vue2写法

子发:事件触发this.$emit('toFather',data)

父收:@toFather="getChild"

                        vue3写法

子发: 

const toFatherval = '想吃小龙虾~~'

const $emit = defineEmits(['toFather'])//声明并定义$emit,绑定触发事件
const toFatherClick = () => {
	$emit('toFather', toFatherval)
}

父收:
const fromChild = ref('还没说')

const getChild = (data) => {
	console.log('child说', data);
	fromChild.value = data
}

状态机vuex, pinia

        vue2:   vuex3

​​​​​​​        1. 下载安装(注意版本与vue版本对应:vue2 :vuex 3; vue3: vuex 4)

yarn add vuex -S

        2. 引入(vuex单独存储数据,所以store文件夹>index.js)

import Vue from 'vue' 
import Vuex from 'vuex' Vue.use(Vuex)

        3. 使用      

import Vue from 'vue' 
import Vuex from 'vuex' Vue.use(Vuex)

//3.1 创建一个数据仓库用来存储等会的交互数据

const store = new Vuex.Store({ 
/**
    state: {},//vuex的基本数据,用来存储变量
    mutations: {},//变更新数据的方法,必须是同步的(如果需要异步使用action)
    getters: {},//从基本数据(state)派生的数据,相当于state的计算属性
    modules: {},//模块化vuex,可以让每一个模块拥有自己的state
    
    actions: {}
    和mutation的功能大致相同,不同之处在于
        1. Action 提交的是 mutation,而不是直接变更状态。 
        2. Action 可以包含任意异步操作。 
   
*/
    //数据存储(存储在state中,  只有交互要传递的数据,才会放入vuex的state中!)
    state: {
        name: '张三',
        list: [],
        obj: {}
        .....
    }

    //getters:相当于computed
    getters:{       
         getName(state ){
           return `名字为${state.name}`
    }}

    //改变,所有state的改变,都必须定义mutation去修改,不能在vue组件中直接改
    mutations: {
        changeName(state, val){
        state.name = 'xxx'
        }
    }

    // actions异步修改 state
    actions:{
      changeAction( state,val){

         setTimeOut(()=>{
             state.name=val
          },1000)    

  }
}
})

//3.2 暴露此仓库

export default store

        3.3 把仓库注入到当前项目中(main.js中)

import store from './xxxxx' 
new Vue({ store, .... })

         组件取值

//1.直接取值:

{{this.$store.state.list}}    
{{this.$store.getters.xx}}


//2.computed取值:(因为vuex的数据无视组件层级,直接在组件计算属性中获取即可)

computed: {
    
    list(){
        return this.$store.state.list
       
    }
}

{{ list }}  ||  this.list


        触发store函数

this.$store.commit( 'changeName','XX'  ) //mutations

this.$store.dispatch( 'changeAction','XX'  ) //actions

pinia

        vue2,vue3都可使用,配置方式不同

        如果你的应用使用的 Vue 版本低于 2.7,你还需要安装组合式 API 包:@vue/composition-api

        如果你正在使用 Vue CLI,你可以试试这个个非官方插件

        本文适用于vue3

        1.安装
yarn add pinia

# 或者使用 npm
npm install pinia
        2.定义store文件方式一 :对象作为参数

        /stores/counter.js

import { defineStore } from 'pinia'

export const useCounterStore1 = defineStore('counter1', {
  //state
  state: () => ({
    sum: 100
  }),

  //getters
  getters: {
    doubleSum(state) {//doubleSum:()=>{}
      return state.sum * 2
    }
  },

  //actions
  actions: {
    addSum() {//错误写法:addSum: () => {}
      console.log('actions:addSum', this.sum--);
    }
  }
})
/** 
与 Vue 的选项式 API 类似,我们也可以传入一个带有 state、actions 与 getters 属性的 Option 对象,
你可以认为 state 是 store 的数据 (data),getters 是 store 的计算属性 (computed),而 
actions 则是方法 (methods)。
*/
        使用store
import { useCounterStore1 } from '@/stores/counter';
const store = useCounterStore1()

//state
console.log(store1.sum);//100
 
//getters
console.log(store1.doubleSum);//200

const com = computed(() => {
  return store1.doubleSum
})
console.log(com.value);//200

  //actions
setTimeout(() => {
  store1.addSum()
  console.log( store1.sum);//99
}, 2000)
  2.定义store文件方式二:方法作为参数
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
//ref() 就是 state 属性  
  const count = ref(0) 

//computed() 就是 getters
  const doubleCount = computed(() => count.value * 2) 

//function() 就是 actions
  function increment() {
    count.value++
  }


//你必须在 setup store 中返回 state 的所有属性
  return { count, doubleCount, increment }
})
        使用store
import { useCounterStore } from '@/stores/counter';
const store = useCounterStore()

//1.访问store中的变量state    
console.log('store:ref===>', store.count);//2

//使用store中的computed值
const doubleValue = computed(() => store.doubleCount)

// 调用store中的异步函数actios
setTimeout(() => {
  store.increment()
  
}, 1000)
    
  3. vue3的main.js引入
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'


const pinia = createPinia()
const app = createApp(App)


app.use(pinia)
app.mount('#app')
4. 使用 Store的注意点
<script setup>



//1.访问store中的变量state    
console.log('store', store.doubleCount);//0

//const { name, doubleCount } = store
// ❌ 这将不起作用,因为它破坏了响应性
// 这就和直接解构 `props` 一样


</script>

        为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs()。它将为每一个响应式属性创建引用。当你只使用 store 的状态而不调用任何 action 时,它会非常有用。请注意,你可以直接从 store 中解构 action,因为它们也被绑定到 store 上:vue

<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()

// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)

// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值