Vue3 数据基础操作

一、知识点

  • defineComponent 构建应用及绑定事件
  • 使用 reactive 绑定数据
  • 使用 ref ( torefs ) 绑定数据
  • 使用 getCurrentInstance 获取当前实例化对象上下文信息
  • watch、watchEffect 数据监听
  • 简单的 TodoList 点餐功能

实例一:使用 reactive 绑定数据

<template>
  <div>
    <h1>使用 reactive 绑定数据</h1>
    <p>{
   
   {state.msg}}</p>
    <p>{
   
   {info}}</p>
    <p>
      <button @click="changeMsg">changeMsg</button>
    </p>
  </div>
</template>
<script>

// Hooks 编程,在 vue 中导入对应的函数方法,面向函数式进行编程
// Vue-composition-API 监测 VCA 复合式 API
// 注意:Vue3热更新有时候会有问题,所以需要手动的刷新页面

import { defineComponent, reactive } from "vue";
export default defineComponent({
  name: 'test1',
  setup() {  // setup钩子函数
    // 使用响应式函数reactive构建proxy响应式对象state
    const state = reactive({
      msg: '时光'
    })
    console.log(state); // state对象是一个proxy拦截对象
    let info = '褚嬴'; // info是一个普通对象,修改后不会被proxy拦截,进而页面也不会动态更新
    const changeMsg = () => { // 在外边定义methods
      state.msg = '时光,你好'
      info = '褚嬴,你好'
    }
    return {  // 使用时,要把对象return出去,才能在template中使用
      state,
      info,
      changeMsg
    }
  }
})
</script>

实例二、使用 ref(toRefs) 绑定数据

<template>
  <div>
    <p>使用v-model双向数据绑定的数据内容是:{
   
   {msg}}</p>
    <p>
      <!-- 自己实现双向数据绑定,监听input事件,动态修改nmsg的值 -->
      <input type="text" ref="myInput" @input="input" :value="nmsg">
    </p>
    <p>使用@input事件动态实现双向数据绑定的数据内容是:{
   
   {nmsg}}</p>
    <p>
      <!-- 使用ref方法动态定义并双向绑定hmsg -->
      <input type="text" v-model="hmsg" @input="hmagInpu">
    </p>
    <p>使用ref方法动态定义并双向数据绑定的数据hmsg是:{
   
   {hmsg}}</p>
    <p>toRefs 来实现在模板中不需要追加 state 调用数据:{
   
   {msg}}</p>
  </div>
</template>
<script>
  import { defineComponent, reactive, getCurrentInstance, toRefs, ref } from "vue";

  export default defineComponent({
    setup() {
      const state = reactive({
        msg: '', 
        nmsg: '',
        cmsg: computed(() => { // 1.计算属性
          return state.msg.length 
        })
      })
      
      // 2.可以使用getCurrentInstance hook 来拿到当前实例化对象上下文信息,但是除非极其特殊的情况,否则不建议这样使用
      const { ctx } = getCurrentInstance(); 
      const input = () => {
        // 在vue3中,因为是面向hooks函数编程,所以,无法通过this拿到当前vue实例化对象
        console.log(ctx.$refs.myInput.value); // 像使用vue2中的this一样,使用ctx(上下文内容信息)
        state.nmsg = ctx.$refs.myInput.value;
      }
      
      // 3.使用ref方法来定义一个响应式监听的对象,在实际开发中我们都是用这种方法来构建响应式对象
      const hmsg = ref('abc');
      const hmagInpu = () => {
        // 在内部使用hmsg的值,需要使用value来获取对应的值
        console.log('获取到的hmsg值是:' + hmsg.value)
      }
      
      return {
        // 4.使用toRefs hook方法方便,访问msg不需要使用state.msg,直接msg就可以获取到
        ...toRefs(state),
        hmsg,
        input,
        hmagInpu
      }
    }
  })
</script>

小结:两种构建响应式对象的方法

1.reactive

1.reactive方法,直接传入一个对象 state ,这个对象就是 proxy 拦截的对象
2.然后再把这个 state 对象直接 return 出去就能被调用
3.在 temolate 中使用 state.msg 来访问
4.在 js 中也使用 state.msg 来访问

2.ref

1.使用 ref 直接声明一个 proxy 响应式对象 msg
2.然后把这个 msg 对象直接 return 出去
3.在 template 中直接使用 { {msg}}
4.注意:在 js 中需要使用 msg.value

实例三、watch、watchEffect 数据监听

<template>
  <div>
    <h1>watch、watchEffect 数据监听</h1>
    <p>{
   
   {msg}}</p>
    <p>{
   
   {msg2}}</p>
    <p>{
   
   {info}}</p>
    <p>
      <button @click="changeMsg">changeMsg</button>
    </p>
    <p>
      <button @click="changeMsg2">changeMsg2</button>
    </p>
  </div>
</template>
<script>
import { defineComponent, reactive, watchEffect, watch, toRefs } from "vue";

export default defineComponent({
  name: 'watch',
  // setup钩子函数
  setup() {
    // 使用响应式函数reactive构建proxy响应式对象state
    const state = reactive({
      msg: '时光',
      msg2: '俞亮',
      changeMsg2: () => {
        state.msg2 = '俞亮,你好'
      }
    })
	const changeMsg = () => { // 在外边定义methods
      state.msg = '时光,你好'
      info = '褚嬴,你好'
    }

    // watch监听只能是 getter/effect 函数、ref、reactive对象或数组
    // 简单监听
    watch(state, () => {
      console.log('观察整个state中属性变化', state.msg) // 只要state中的值有变化,就会打印
    })
    // 监听指定的信息
    watch(() => state.msg, (newVal, oldVal) => {
      console.log('01-msg的新值是:' + newVal + '-------旧值是:' + oldVal);
    })
    // 监听多个属性(数组形式)
    watch([() => state.msg, () => state.msg2], (newVal, oldVal) => {
      console.log('02-msg的新值是:' + newVal + '-------旧值是:' + oldVal) // 02-msg的新值是:时光,你好,俞亮-------旧值是:时光,俞亮
    })
    // 不需要指定监听的属性
    watchEffect(() => {
      // 程序运行时,初始化就会执行一次,完成监听准备工作
      console.log('03-watchEffect监听 state 中数据变化:', state.msg) // 有点像computed计算属性,用到的数据发生改变才会执行
    })

    // 使用时,要把对象return出去,才能在template中使用
    return {
      ...toRefs(state),
      info,
      changeMsg
    }
  }
})
</script>

简单应用:TodoList 点餐

<template>
  <div>
    <h1>TodoList 点餐</h1>
    <h2>菜单列表</h2>
    <ul>
      <li v-for="(item, index) in list" :key="index">
        {
   
   {item.name}} 价格 {
   
   {item.price}}
        <button @click="add(index)">点餐</button>
      </li>
    </ul>
    <h2>已点菜单</h2>
    <ul>
      <li v-for="(item, index) in aList" :key="index">
        {
   
   {item.name}} 价格 {
   
   {item.price}}
        <button @click="remove(index)">取消</button>
      </li>
    </ul>
    <h3>一共点了 {
   
   {count}} 道菜,消费 {
   
   {allPrice}} 元</h3>
  </div>
</template>

<script>
import { defineComponent, reactive, computed, toRefs } from "vue";

export default defineComponent({
  setup() {
  
    // 浮点数相加处理
    const add = (num1, num2) => {
      // 将第一个数转成字符串,取小数点后的部分,记录小数点后的位数
      const a1 = ('' + num1).split('.')[1] ? ('' + num1).split('.')[1].length : 0;
      const a2 = ('' + num2).split('.')[1] ? ('' + num2).split('.')[1].length : 0;
      // 取较大的位数,获得10的指数幂
      const m = Math.pow(10, Math.max(a1, a2));
      // 处理成整数相加,再除以指数
      return (num1 * m + num2 * m) / m;
    }
    
    const state = reactive({
      list: [
        {
          name: '四喜丸子',
          price: 20.88
        },
        {
          name: '狮子头',
          price: 30.88
        },
        {
          name: '辣子鸡',
          price: 40.88
        },
        {
          name: '糖醋鲤鱼',
          price: 50.88
        },
      ],
      aList: [],
      count: computed(() => {
        return state.aList.length;
      }),
      allPrice: computed(() => {
        let allPrice = 0;
        state.aList.map(item => {
          // allPrice += item.price // js 中,浮点数相加会与实际结果有差异,因为在 js 编译的过程中,浮点数保存并不是精确的
          allPrice = add(allPrice, item.price);
        })
        return allPrice
      }),
      add: (index) => {
        console.log('你点的是:', state.list[index]);
        state.aList.push(state.list[index]);
      },
      remove: (index) => {
        console.log('你取消了:', state.aList[index]);
        state.aList.splice(index, 1)
      }
    })
    return {
      ...toRefs(state)
    }
  }
})
</script>

<style lang="scss" scoped>
  li{
    margin:20px;
  }
</style>

Guess you like

Origin blog.csdn.net/xiamoziqian/article/details/111171021