Vue3中常用的语法详细分解(响应式数据,声明响应式数据,自定义事件,计算属性,监听器)

简介: Vue3中常用的语法详细分解(响应式数据,声明响应式数据,自定义事件,计算属性,监听器)

1. 创建Vue实例

Vue3使用API一律是函数式风格所以和new告别了。

// Vue3.0
import {createApp} from 'vue'
createApp(App).use(router).use(store).mount('#app')
// Vue2.0
import Vue from 'vue'
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

1.1 其他的区别

全局

// vue2
import Vue from 'vue'
Vue.component(...)
// vue3
import {createApp} from 'vue'
let app = createApp(App)
app.component(...)

filter 没有了

全局


Vue.component -> app.component

filter没了 filter -> computed/method

v-model value+input -> value+input || modelValue+update:modelValue

函数h render(h) -> import {h} from ‘vue’

data data: {} || data(){} -> data(){}

异步组件 ()=>import(’…’) -> defineAsyncComponent(()=>import(’…’))

事件 e m i t 、 emit、 emit、on、… -> $emit

其他 …

2. 响应式数据

模板定制

<template>
  <div class="hello" style="border:1px solid">
    <h1 ref="root">{{ msg }}</h1>
    {{state.count}} double is {{double}}
    <button @click="add">+</button>
  </div>
</template>

2.1 声明响应式数据

// Vue2
export default {
  // ....
  data() {
    return {
      state: {
        count: 0
      }
    };
  },
}
// Vue3 reactive 
export default {
  // ....
  setup(){
    const state = reactive({
      count:0
    })
    return {state}
  }
}

2.2 自定义事件

// Vue2
export default {
  // ....
  methods: {
    add() {
      this.state.count++;
    }
  },
}
// Vue3
export default {
  // ....
  setup(){
    const add = () => {
      state.count++
    }
    return {add}
  }
}

2.3 计算属性

// Vue2
export default {
  // ...
  computed: {
    double() {
      return this.state.count * 2;
    }
  },
}
// Vue3
export default {
  // ...
  setup(){
    const double = computed (() => state.count * 2 )
    return {double}
  }
}

2.4 监听器

// Vue2
export default {
  // ...
  watch: {
    count: value => {
      console.log("count is changed:", value);
    }
  }
}
// Vue3
export default {
  // ...
  setup(){
    watch(
      () => state.count,
      value => {
        console.log('state change :',value)
      }
    )
  }
}

2.5 生命周期及其获取Dom元素

// Vue2
<div ref="dom"></div>
export default {
  // ...
  mounted() {
    this.$refs.dom.style.color = "red";
  }
}
// Vue3
<h1 ref="myRef">7777777777777777777</h1>
export default {
  // ...
  setup() {
    // ref 创建一个响应式的数据对象
    const myRef = ref(null);
    onMounted(() => {
      console.dir(myRef);
       const dom = myRef.value
      dom.style.color = 'red'
    });
    return {
      myRef
    }
  },
}

3. API 列表

const {
  createApp,
  reactive, // 创建响应式数据对象
  ref, // 创建一个响应式的数据对象
  toRefs, // 将响应式数据对象转换为单一响应式对象
  isRef, // 判断某值是否是引用类型
  computed, // 创建计算属性
  watch, // 创建watch监听
  // 生命周期钩子
  onMounted,
  onUpdated,
  onUnmounted,
} = Vue

3.1 setup使用composition API的入口

setup函数会在 beforeCreate之后 created之前执行

setup(props,context){
    console.log('setup....',)
    console.log('props',props) // 组件参数
    console.log('context',context) // 上下文对象
} 

3.2 reactive

reactive() 函数接受一个普通对象 返回一个响应式数据对象

const state = reactive({
        count: 0,
        plusOne: computed(() => state.count + 1)
    })

3.3 ref 与 isRef

ref 将给定的值(确切的说是基本数据类型 ini 或 string)创建一个响应式的数据对象

isRef 其实就是判断一下是不是ref生成的响应式数据对象

 // 定义创建响应式数据
    const time = ref(new Date())
    // 设置定时器为了测试数据响应
    setInterval(() => time.value = new Date(), 1000)
    // 判断某值是否是响应式类型
    console.log('time is ref:', isRef(time))
    console.log('time', time)
    console.log('time.value', time.value)
    // 我们看看模板里面我们这样展示
    template: `
        <div>
            <div>Date is {{ time }}</div>
        </div>
    `

3.4 toRefs

toRefs就是ref的批量操作

toRefs 可以将reactive创建出的对象展开为基础类型

1.
// 如果不用toRefs
    const state = reactive({
        count: 0,
        plusOne: computed(() => state.count + 1)
    })
    return {
        state
    }
    // 模板渲染要这样写
    template: `
    <div>
        <div>count is {{ state.count }} </div>
        <div>plusOne is {{ state.plusOne }}</div>
    </div>
    `
    // 我们再看看用了toRefs
    const state = reactive({
        count: 0,
        plusOne: computed(() => state.count + 1)
    })
    return {
        ...toRefs(state)
    }
    // 模板渲染要这样写
    template: `
    <div>
        <div>count is {{ count }} </div>
        <div>plusOne is {{ plusOne }}</div>
    </div>
    `

3.5 watch 定义监听器

这个其实没有什么新东西,需要手动指定

watch(() => 谁,()=>{})
watch(() =>[a,b....], ()=>{})
watch(() => state.count * 2, val => {
        console.log(`count * 2 is ${val}`)
 })

3.5.1 watchEffect 自动监听

自动监听,当watchEffect内部使用了某个值会自动监听这个值变化,当这个值变化的时候触发

 watchEffect((invalidate) => { 
  console.log('a变了',a)     
 })
invalidate: 参数是一个函数,放监听器失效的时候触发。监听器什么时候会失效?stop的时候、或者组件销毁
invalidate(()=>{})

3.5.2 停止监听

 let stop = watchEffect((invalidate) => {})
 let stop1 = watch(() => 谁,()=>{})
 stop()
 stop1()

3.6 ffect 副作用函数

响应式对象修改会触发这个函数

    // 副作用函数
    effect(() => {
        console.log('数值被修改了..',state.count)
    })

3.7 computed 计算属性

const state = reactive({
    count: 0,
    plusOne: computed(() => state.count + 1)
})

3.8 provide/inject 依赖注入

// 外部组件
setup(){ 
  provide(名字,值【可以是任何类型】)  
}
// 内部
setup(){ 
  const a = inject(名字,可选参:默认值)

toRaw 与 markRaw

toRaw 拿出reactive、ref、readonly这个方法转换前的原始互数据,对原始数据操作不会被监听

markRaw 保持一个数据永远是原始数据不会被监听

unRef 、toRef、customRef

unRef :获取ref对象的原始数据,那为什么不用toRaw

toRaw连着value一起拿,获取出来就是 => {value:xxx}

unRef是ref专用 => xxx

toRef: 也是把一个数据转成ref对象,但是的ref专有一些区别

let json = {a:12}
const b = ref(json.a)
b.value++ 
console.log(json,b)  // {a:12} // {value:13}
const a = toRef(json,'a')
a.value++ 
console.log(json,a)  // {a:13} // {value:13}

ref toRef

相当于把原始数据拷贝,以后操作与原始数据无关 依然存在引用关系

改ref对象后模板会重新渲染 不会触发模板渲染

customRef:自定义ref

function myCustomRef(){
  let _val = 12 
  return customRef((track,trigger)=>{
    return {
      get(){
        track()
        return _val
      },
      set(newVal){
        _val = newVal
        // 通知vue,请重新渲染
        trigger()
      }
    }
  })
}
setup(){
    const arr = myAjax('xxxx',[])
    return {
        arr
    }
}
function myAjax(url,initval){
  let _data = initval 
  return customRef((track,trigger)=>{
    axios(url).then(res=>{
      _data = res._data
      trigger()
    })
    return {
      get(){
        track()
        return _data
      },
      set(newVal){
        _data = newVal
        // 通知vue,请重新渲染
        trigger()
      }
    }
  })
}

Vue2                     |                Vue3

--------------------------------------------------

beforeCreate             |             setup(替代)

created                   |             setup(替代)

beforeMount            |            onBeforeMount

mounted                   |            onMounted

beforeUpdate             |               onBeforeUpdate

updated                   |               onUpdated

beforeDestroy             |              onBeforeUnmount

destroyed                 |               onUnmounted

errorCaptured             |               onErrorCaptured

4. Teleport 组件

Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML

// vue3 新添加了一个默认的组件就叫 Teleport,我们可以拿过来直接使用,它上面有一个 to 的属性,它接受一个css query selector 作为参数,这就是代表要把这个组件渲染到哪个 dom 元素中
  <teleport to="#modal">
    <div id="center">
      <h1>this is a modal</h1>
    </div>
  </teleport>

4.1 Suspense - 异步组件好帮手

定义一个异步组件,在 setup 返回一个 Promise,AsyncShow.vue

<template>
  <h1>{{result}}</h1>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  setup() {
    return new Promise((resolve) => {
      setTimeout(() => {
        return resolve({
          result: 42
        })
      }, 3000)
    })
  }
})
</script>

使用 async await 改造一下异步请求, 新建一个 DogShow.vue 组件

<template>
  <img :src="result && result.message">
</template>
<script lang="ts">
import axios from 'axios'
import { defineComponent } from 'vue'
export default defineComponent({
  async setup() {
    const rawData = await axios.get('https://dog.ceo/api/breeds/image')
    return {
      result: rawData.data
    }
  }
})
</script>
<Suspense>
  <template #default>
    <async-show />
    <dog-show />
  </template>
  <template #fallback>
    <h1>Loading !...</h1>
  </template>
</Suspense>

5. 路由Vue-router

5.1 创建路由

// Vue2
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes:  [
    // 路由配置不变
  ]
})
// Vue3
const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes:  [
    // 路由配置不变
  ]
})

5.2 使用路由

// Vue2
export default {
  name: "Home",
  methods: {
    goHome() {
      this.$router.push('Home')
    }
  }
};
// Vue3
export default {
  setup() {
    const router = useRouter()
    const goHome = () => router.push('Home')
    return { goHome};
  }
};

6.0 统一状态管理Vuex

6.1 创建Vuex

// Vue2
export default new Vuex.Store({
  state: {
    count:1
  },
  mutations: {
    inc(state){
      state.count ++ 
    }
  },
  actions: {
  },
  modules: {
  }
})
// Vue3
export default Vuex.createStore({
  state: {
    count:1
  },
  mutations: {
    add(state){
      state.count ++ 
    }
  },
  actions: {
  },
  modules: {
  }
});

6.2 使用Vuex

// Vue2
export default {
  name: "Home",
  data() {
    return {
        state: this.$store.state
    };
  },
  computed: {
    double() {
      return this.$store.state.count * 2;
    },
  },
  methods: {
    add() {
      this.$store.commit("add");
    }
  }
};
// Vue3
import { computed,  reactive } from "vue";
import { useStore } from "vuex";
export default {
  setup() {
    const store = useStore()
    const state = store.state
    const double = computed(() => store.state.count * 2)
    const add = () => {
      store.commit("add");
    };
    return { state, add ,double};
  }
};
相关文章
|
13天前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
30 7
|
14天前
|
前端开发 数据库
芋道框架审批流如何实现(Cloud+Vue3)
芋道框架审批流如何实现(Cloud+Vue3)
36 3
|
13天前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
33 1
|
13天前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
34 1
|
3天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
3天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
3天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
3天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
2天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
4天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。