0610-Vue(响应式)

310 阅读4分钟

测试数据的响应性

子组件代码:

js部分:

import {ref,toRefs,reactive,toRef} from 'vue';

name: "MyTest",
//props 必不可少  最好写成对象
// props:['p_data'],
props:{
  'parent-data':{
    type:Number,
    required:true,
  },
  'test_again':{
    type:String,
    required: true
  }
},
setup(props,{attrs,slots,emit,expose}){
  //父组件传递数据
  console.log(props)
  //父组件传递的属性
  // console.log(context.attrs)
  // console.log(context.slots)
  // console.log(context.emit)
  // console.log(context.expose)
  // 因为context是普通的JS对象,所以支持直接解构
  console.log(attrs);
  console.log(slots);
  console.log(emit);
  console.log(expose);
  //跟上面的一样 但是有点搞不懂它究竟可以干啥???

  let normal_a = 5;
  let normal_b = 6;
  const ref_a = ref(15);
  const ref_b = ref(16);
  const normal_obj_a = {test_num1:10,test_num2:20}
  // const ref_obj_b = toRefs({test_num_ref1:18,test_num_ref2:28})
  //第一版这样写之后 报错了 :
  // toRefs() expects a reactive object but received a plain one.
  //第二版
  const ref_obj_reactive = reactive({test_num_ref1:18,test_num_ref2:28})
  const ref_obj_b = toRefs(ref_obj_reactive)
  function calculateFuc(){
    normal_a++;
    normal_b--;
    ref_a.value++;
    ref_b.value--;
    normal_obj_a.test_num1++;
    ref_obj_b.test_num_ref1.value++;
  }
  //父组件传数据测试=======================================
  // const {parentData }= props
  // console.log(parentData)
  //直接解构 不用toRef 报错
  //Getting a value from the `props` in root scope of `setup()` will cause the value to lose reactivity vue/no-setup-props-destructure
  //props 是响应性的切记不要直接解构
  const parentData = toRef(props,'parentData')
  console.log(parentData.value)
  //得出结论:起初我以为单个值传递给props的时候,不需要解构,验证之后 想法错误 不管父级组件传来的数据是什么类型,props为了响应性都给套了有个外壳
  //关于暴露
  return{
    normal_a,
    normal_b,
    ref_a,
    ref_b,
    normal_obj_a,
    ref_obj_b,
    calculateFuc,
    parentData,
  }
},

template部分:

<fieldset id="my-test">
  <legend>这是自己搞的测试单文件</legend>
  <p><button style="border: 2px solid red" @click="calculateFuc">点击计算函数</button></p>
  <ol>
    <li>normal_a:==>{{normal_a}}</li>
    <li>normal_b:==>{{normal_a}}</li>
    <li>ref_a:==>{{ref_a}}</li>
    <li>ref_b:==>{{ref_b}}</li>
    <li>normal_obj_a.test_num1:==>{{normal_obj_a.test_num1}}</li>
    <li>ref_obj_b:==>{{ref_obj_b.test_num_ref1}}</li>
  </ol>
  <hr>
  <ol>
    <li>定义数据得出结论,单一数据通过setup返回之后,到渲染的时候单纯的就说一个数字,想要保持响应性,利用ref + value</li>
    <li>数组的话</li>
  </ol>
  <h4>父组件传递过来的数据(单个值的情况)为:{{parentData}}</h4>
  <hr>
  <h5>测试一下关于插槽的知识点</h5>
  <slot name="default" :test_slot="ref_b"></slot>
  <slot name="sum"></slot>
</fieldset>

css部分

<style scoped>
#my-test{
  border:2px solid #2c3e50 ;
  background-color: #ddd;
}
</style>

父组件部分

js代码

<script>
import { ref} from 'vue'
import SetupComponent from './components/setup'
import MyTest from "./components/my-test";
export default {
  name: "combined-main.vue",
  //  我开始发挥啦~
  data(){
    return{
      p_a:100,
    //  向子级组件传递的不管是对象还是数值 都需要解构
      p_attr:'爹给儿的属性',
      p_test_context:'如果在子组件的props中引入,那么该数据就应该出现在子组件中的setup的props而不是attrs'
    }
  },
  components: {
    SetupComponent,
    MyTest,
  },
  setup(){
    const childrenRef = ref(null)
    return{
      childrenRef
    }
  },

}
</script>

template部分

<template>
  <h1>组合API页</h1>
  <p>测试在一个页面上添加一个子组件,它的文件结构!</p>
  <fieldset>
    <legend>这是example1的父组件</legend>
    <div id="example1">
      <p>这里边的标签是正常使用的!</p>
      <p>测试 子组件, 添加一个带有 setup 函数的子组件</p>
      <setup-component ref="childrenRef"></setup-component>
      <p>从子组件通过ref访问到的数据{{childrenRef}}</p>
      <!--    以下是我自己要写的测试my-test.vue-->
      <MyTest :parent-data="p_a" :test_attr=" p_attr" :test_again="p_test_context">
<!--        测一下我比较迷糊的插槽-->
        <template v-slot:default="getChildProps" >
          <div style="background-color:pink;width: 300px;border: 3px dashed orange">
            <p>我是在父组件中给子组件添加的插槽,想测试一下子组件如何向父组件通过插槽传递数据的</p>
            <p>子组件通过插槽传过来的数据为:<span style="color: cornsilk">{{getChildProps.test_slot}}</span></p>
          </div>
        </template>
<!--        注释插槽-->
        <template v-slot:sum>
          <ol>
            <li>父传子 千年不变的 规律 找props  并且为了其响应性 不可以在子组件中直接解构props 也不可以更改数据</li>
            <li>子传父 目前有三种方式
              <ol>
                <li>从父组件定义一个函数,在子组件emit中传入,执行的时候传递数据</li>
                <li>slot方式子组件在slot标签中任意定义属性,最后父组件的template中 直接插槽名字.属性</li>
                <li>还有一种就是ref,通过子组件利用expose暴露,接着父组件定义ref=attrname,接着父组件的setup 声明 attrname=ref(null),返回attrname 然后父组件就可以用到子组件传来的数据啦</li>
              </ol>
            </li>
          </ol>
        </template>
      </MyTest>
      <p><button style="background-color: #42b983;border: 3px solid #dddddd" @click="p_a++">操作往子组件传递的数p_a:{{p_a}}</button></p>
      <h5>经过测试 子组件用toRef()解构父组件传递的数据成功,如果不用toRef 直接报错 说失去响应性</h5>
    </div>
  </fieldset>
</template>

部分知识点: 在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。

因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。

在 Vue 3.0 中,我们可以通过一个新的 ref 函数使任何响应式变量在任何地方起作用

ref 接收参数并将其包裹在一个带有 value property 的对象中返回,然后可以使用该 property 访问或更改响应式变量的值:

provide&inject

provide 有两个参数 :name&& value

inject 参数也有两个。只不过第二个是可选的。name value(默认属性值)

为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide值时使用 ref或者reactive,如果想要对提供的信息进行修改的话,一般在provide方进行修改,涉及到inject方动作影响provide方提供的数据的情况,那么官方建议“有时我们需要在注入数据的组件内部更新 inject 的数据。在这种情况下,我们建议 provide 一个方法来负责改变响应式 property。”

最后,如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly

export default {
  components: {
    MyMarker
  },
  setup() {
    const location = ref('North Pole')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })

    const updateLocation = () => {
      location.value = 'South Pole'
    }

    provide('location', readonly(location))
    provide('geolocation', readonly(geolocation))
    provide('upd