Vue 基础之 setup、ref 及 reactive、toRef 及 context、TodoList、computed、watch 及 watchEffect、生命周期函数新写法、provide

一、Vue 基础之 setup、ref 及 reactive、toRef 及 context、TodoList、computed、watch 及 watchEffect、生命周期函数新写法、provide 及 inject
  1. setup 是在 created 实例被完全初始化之前执行的函数,接收 propscontext 参数。在 setup 中返回出来的数据和方法可以被模版、外部等使用,但不能使用外部的数据和方法,因为此时 app 实例并没有被挂载,同时 setup 中是不能使用 this 以及实例上的方法,如下所示:
const app = Vue.createApp({
  template: `
    <div @click="handleClick">{{name}}</div>
  `,
  methods: {
    test() {
      console.log(this.$options.setup());
    }
  },
  mounted() {
    this.test();
  },
  setup(props, context) {
    return {
      name: 'Tom',
      handleClick: () => {
        alert(123)
      }
    }
  }
});
const vm = app.mount('#root');
  1. ref、reactive 响应式的引用,原理是通过 proxy 对数据进行封装,当数据变化时,触发模版等内容的更新。ref 是可以处理基础类型的数据,如 ref('Tom')proxy 'Tom' 变成 proxy({value: 'Tom'}) 这样的一个响应式引用,而响应式引用在改变值以后,页面会跟着变化的。reactive 处理非基础类型的数据,如 reactive({name: 'Tom'})proxy {name: 'Tom'} 变成 proxy({name: 'Tom'}) 这样的一个响应式引用。readonly 可以对响应式引用进行限制,通过 readonly 处理返回的对象是不可以被响应式修改的。toRefs 可以将 reactive 中的数据处理成响应式的数据,如 toRefs proxy({name: 'Tom', age: 24}) 变成 { name: proxy({value: 'Tom'}), age: proxy({value: 24})} ,如下所示:
const app = Vue.createApp({
  template: `
    <div>{{name}}</div>
  `,
  setup(props, context) {
    // const { ref } = Vue;
    // let name = ref('Tom');
    // setTimeout(() => {
    //  name.value = 'Jack'
    // }, 2000)
    // return { name }
    
    const { reactive, readonly, toRefs } = Vue;
    const nameObj = reactive({name: 'Tom', age: 24});
    // const nameObj = reactive([123]);
    // const copyNameObj = readonly(nameObj);
    setTimeout(() => {
      nameObj.name = 'Jack'
      // nameObj[0] = 456
      // copyNameObj[0] = 456
    }, 2000)
    const { name, age } = toRefs(nameObj);
    return { nameObj, copyNameObj, name, age }
  }
});
const vm = app.mount('#root');
  1. toRef,当对象里面没有对应属性值的时候,又想要这个属性值具备响应式特性的时候,可以使用 toRef,如下所示:
const app = Vue.createApp({
  template: `
    <div>{{age}}</div>
  `,
  setup(props, context) {
    const { reactive, toRef } = Vue;
    const data = reactive({name: 'Tom'});
    const age = toRef(data, 'age');
    setTimeout(() => {
      age.value = 24
    }, 2000);
    return { age }
  }
});
const vm = app.mount('#root');
  1. setupcontext 参数中,包括 attrs、slots、emit 等,attrs 是父组件传递过来的 none-props 属性,slots 是实现之前 this.$slotsemit 是实现之前 this.$emit,如下所示:
const app = Vue.createApp({
  methods: {
    handleChange() {
      alert('change');
    }
  },
  template: `
    <child @change="handleChange">parent</child>
  `,
});

app.component('child', {
  template: `
    <div @click="handleClick">123</div>
  `,
  setup(props, context) {
    const { h } = Vue;
    const { attrs, slots, emit } = context;
    function handleClick() { emit('change'); }
    return { handleClick }
  }
});
const vm = app.mount('#root');
  1. 实现 TodoList,如下所示:
// 关于 List 操作的内容进行了封装
const listRelativeEffect = () => {
  const { reactive } = Vue;
  const list = reactive([]);
  const addItemToList = (item) => {
    list.push(item);
  }
  return { list, addItemToList }
}

// 关于 inputValue 操作的内容进行了封装
const inputRelativeEffect = () => {
  const { ref } = Vue;
  const inputValue = ref('');
  const handleInputValueChange = (e) => {
    inputValue.value = e.target.value
  }
  return { inputValue, handleInputValueChange }
}

const app = Vue.createApp({
  setup() {
    // 流程调度中转
    const { list, addItemToList } = listRelativeEffect();
    const { inputValue, handleInputValueChange } = inputRelativeEffect();
    return {
      list, addItemToList, inputValue, handleInputValueChange
    }
  },
  template: `
    <div>
      <div>
        <input :value="inputValue" @input="handleInputValueChange" />
        <button @click="() => addItemToList(inputValue)">提交</button>
      </div>
      <ul>
        <li v-for="(item, index) in list" :key="index">{{item}}</li>
      </ul>
    </div>
  `
});
const vm = app.mount('#root');
  1. computed 计算属性,如下所示:
const app = Vue.createApp({
  setup() {
    const { ref, computed, reactive } = Vue;
    // const count = ref(0);
    const countObj = reactive({count: 0});
    const handleClick = () => {
      // count.value += 1;
      countObj.count += 1;
    }
    let countAddFive = computed({
      get: () => {
        // return count.value + 5;
        return countObj.count + 5;
      },
      set: (param) => {
        // count.value = param - 5;
        countObj.count = param - 5;
      }
    })
    
    setTimeout(() => {
      countAddFive.value = 100;
    }, 3000)
    
    return { count, countObj, countAddFive, handleClick, }
  },
  template: `
    <div>
      <span @click="handleClick">{{countObj.count}}</span> -- {{countAddFive}}
    </div>
  `
});
const vm = app.mount('#root');
  1. watch 侦听器,具备一定的惰性 lazy,参数可以拿到原始和当前值,可以侦听多个数据的变化,用一个侦听器承载。watchEffect 侦听器,偏向于 effect,立即执行,没有惰性 immediate,不需要传递你要侦听的内容,自动会感知代码依赖,不需要传递很多参数,只要传递一个回调函数,不能获取之前数据的值,如下所示:
const app = Vue.createApp({
  setup() {
    const { reactive, watch, toRefs, watchEffect } = Vue;
    const nameObj = reactive({
      name: 'Tom', englishName: 'Jack'
    });
    watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng], [prevName, preEng]) => {
      console.log(curName, prevName, '---', curEng, preEng);
    }, { immediate: true });
    
    const stop = watchEffect(() => {
      console.log(nameObj.name);
      console.log(nameObj.englishName);
      setTimeout(() => {
        stop();
      }, 5000)
    })
    
    const { name, englishName } = toRefs(nameObj);
    return { name, englishName }
  },
  template: `
    <div>
      <div>
        Name: <input v-model="name" />
      </div>
      <div>
        Name is {{ name }}
      </div>
      <div>
        EnglishName: <input v-model="englishName" >
      </div>
      <div>
        EnglishName is {{EnglishName}}
      </div>
    </div>
  `
});
const vm = app.mount('#root');
  1. 生命周期函数,beforeMount -> onBeforeMount,mounted -> onMounted,beforeUpdate -> onBeforeUpdate,beforeUnmount -> onBeforeUnmount,unmounted -> onUnmountedonRenderTracked 是当页面渲染后 Vue 会重新收集响应式的依赖而自动执行,也就是每次渲染后重新收集响应式依赖,onRenderTriggered 是每次触发页面重新渲染时自动执行,如下所示:
const app = Vue.createApp({
  setup() {
    const { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onRenderTracked, onRenderTriggered } = Vue;
    const name = ref('Tom');
    onBeforeMount(() => {
      console.log('onBeforeMount')
    })
    onMounted(() => {
      console.log('onMounted')
    })
    onBeforeUpdate(() => {
      console.log('onBeforeUpdate')
    })
    onUpdated(() => {
      console.log('onUpdated')
    })
    onRenderTracked(() => {
      console.log('onRenderTracked')
    })
    onRenderTriggered(() => {
      console.log('onRenderTriggered')
    })
    const handleClick = () => {
      name.value = 'Tom'
    }
    return { name, handleClick }
  },
  template: `
    <div @click="handleClick">{{name}}</div>
  `
});
const vm = app.mount('#root');
  1. provide、inject,CompositionAPI 的语法下,ref 获取真实的 DOM 元素节点,如下所示:
const app = Vue.createApp({
  setup() {
    const { provide, ref, readonly } = Vue;
    const name = ref('Tom');
    provide('name', readonly(name));
    provide('changeName', (value) => {
      name.value = value;
    });
    return { }
  },
  template: `
    <div>
      <child />
    </div>
  `,
});

app.component('child', {
  setup() {
    const { inject } = Vue;
    const name = inject('name');
    const changeName = inject('changeName');
    const handleClick = () => {
      changeName('Jack')
    }
    return { name, handleClick }
   },
  template: `
    <div @click="handleClick">{{name}}</div>
    `
});

/**
const app = Vue.createApp({
  setup() {
    const { ref, onMounted } = Vue; 
    const hello = ref(null);
    onMounted(() => {
      console.log(hello.value);
    })
    return { hello }
  },
  template: `
    <div>
      <div ref="hello">hello world</div>
    </div>
  `
});
**/

const vm = app.mount('#root');
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值