Vue3.0学习 - 第三节,Vue3 组合api的理解

2022-08-02 14:45:34

写一个todolist,大概长这样

vue2.xx 语法

<template>

  <div>
    <from>
      <input type="text" v-model="stu.id">
      <input type="text" v-model="stu.name">
      <input type="text" v-model="stu.age">
      <input type="submit" @click="addStu">
    </from>
    <ul>
      <li v-for="(sta,index) in stus" :key="index" @click="remStu(index)">
        {{sta.name}} -- {{sta.age}}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  components: {},
  data() {
    return {
      stus: [
        { id: 1, name: "zs", age: 18 },
        { id: 2, name: "ww", age: 1892 },
        { id: 3, name: "ls", age: 120 },
        { id: 4, name: "zz", age: 19 },
      ],
      stu: {
        id: "",
        name: "",
        age: "",
      },
      // 新增功能1的数据
    };
  },
  methods: {
    remStu(index) {
      this.stus.splice(index, 1);
    },
    addStu(e) {
      e.preventDefault();
      const stu = Object.assign({}, this.stu);
      this.stus.push(stu);
      this.stu.id = "";
      this.stu.name = "";
      this.stu.age = "";
    },

    // 新增功能1的业务逻辑
  },
};
</script>

效果长这样

有新增功能,有删除功能(直接点 li 标签就删除它)。

vue2是数据和功能分离,创建一个功能1,需要创建功能1的数据,在创建功能1的业务逻辑

Vue3 期望用组合API 的方式来解决一个应用中,数据和功能分离的问题。即方法和 data 里的数据隔了一层进行调用的问题

组合api

代码大概长这样

<template>
  <div>
    <h3>{{count}}</h3>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  name: "App",
  // setu函数是组合api的入口函数
  setup() {
    //   let count = 0;
    // 定义了一个名称叫做count变量,这个变量的初始值是0
    // 这个变量发生改变之后,vue会自动更新UI
    let count = ref(0);
    // 在组合api中,如果想定义方法,不用定义到methods中,直接定义即可
    function myFn() {
      // alert(123)
      console.log("count", count.value);
      count.value += 1;
    }
    // 注意点:
    // 在组合api中定义的变量/方法,要想在外界使用,必须通过 return{xxx,xxx} 暴露出去
    return { count, myFn };
  },

  components: {},

  methods: {},
};
</script>

效果长这样

点击按钮 数字 +1

setup 、ref 、return

什么是setup ,什么是ref ,return 的又是什么鬼   可以先看下这篇文章点击这里

# ref什么是ref

Ref是这样的一种数据结构:它有个key为Symbol的属性做类型标识,有个属性value用来存储数据。这个数据可以是任意的类型,唯独不能是被嵌套了Ref类型的类型。

Ref类型的数据,是一种响应式的数据。

Ref写法简单,但也有弊端,它只能监听一些如数字、字符串、布尔之类的简单数据。复杂数据需要用到以后讲的reactive 。(实际上也可以用Ref来封装对象,只不过在访问上多一层value,稍微麻烦了一些)。

具体Ref 数据的结构长这样:

要更改它的数据,主要更改和关注它的value 值就够了

# setup

setup,就是我们最近老是能听到的 Composition API,组合式 API。关于这个 API 的细节,还请参阅官方文档,这里我只期望说一下简单的内容

setup选项应该是一个接受propscontext的函数。此外,我们从setup 返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。

也就是说,setup中创建并return的所有东西,都将被得到外部的解析,无论是过去在data中创建的数据也好,还是在methods创建的方法也好,都将变成允许被响应式地使用,仿佛 Vue2 中的这些 API 都被融合在一起了一样,而实际上 Vue3 也是为了实现这个目的。

有了这两点认识(refsetup),我想上面的代码就变得简单了起来。回到刚刚的 Todo List,我们用这个 API 来实现试一下。

用组合 API 来实现 Todo List

<template>
  <div>
    <ul>
      <li v-for="(sta, index) in state.stus" :key="index" @click="remStu(index)">
        {{ sta.id }}: {{ sta.name }} -- {{ sta.age }}
      </li>
    </ul>
  </div>
</template>

<script>
import { reactive } from "vue";
export default {
  name: "App",
  // setu函数是组合api的入口函数
  setup() {
      
    let state = reactive({
      stus: [
        { id: 1, name: "zs", age: 18 },
        { id: 2, name: "ww", age: 1892 },
        { id: 3, name: "ls", age: 120 },
        { id: 4, name: "zz", age: 19 },
      ],
    });
    function remStu(index){
        state.stus.splice(index, 1);
    }
    // let {state,remStu} = removeStu()
    return {state,remStu}
  },

  components: {},

  methods: {

  },
};
// 抽离
function removeStu(){
   let state = reactive({
      stus: [
        { id: 1, name: "zs", age: 18 },
        { id: 2, name: "ww", age: 1892 },
        { id: 3, name: "ls", age: 120 },
        { id: 4, name: "zz", age: 19 },
      ],
    });
    function remStu(index){
        state.stus.splice(index, 1);
    }
    return {state,remStu}
}
</script>

这里引进了reactive ,和ref 一样,具体了解参考这篇文章,简单来说,就是复杂类型版本的ref。只要你看懂了前文,这部分的代码对你来说不成问题。

ref函数只能监听简单类型的变化,不能监听复杂类型的变化(对象/数组)

todolist 新增删除

<template>
  <div>
    <form>
      <input type="text" v-model="state2.stu.id" />
      <input type="text" v-model="state2.stu.name" />
      <input type="text" v-model="state2.stu.age" />
      <input type="submit" @click="addStu" />
    </form>
    <ul>
      <li
        v-for="(sta, index) in state.stus"
        :key="index"
        @click="remStu(index)"
      >
        {{ sta.id }}: {{ sta.name }} -- {{ sta.age }}
      </li>
    </ul>
  </div>
</template>

<script>
import { reactive } from "vue";
export default {
  name: "App",
  // setu函数是组合api的入口函数
  setup() {
    let state = reactive({
      stus: [
        { id: 1, name: "zs", age: 18 },
        { id: 2, name: "ww", age: 1892 },
        { id: 3, name: "ls", age: 120 },
        { id: 4, name: "zz", age: 19 },
      ],
    });
    function remStu(index) {
      state.stus.splice(index, 1);
    }
    let state2 = reactive({
      stu: {
        id: "",
        name: "",
        age: "",
      },
    });
    function addStu(e) {
      e.preventDefault();
      const stu = Object.assign({}, state2.stu);
      state.stus.push(stu);
      state2.stu.id = "";
      state2.stu.name = "";
      state2.stu.age = "";
    }
    
    return { state, remStu, state2, addStu };
  },
};

</script>

效果这样

和最开始我们写的 Todo List 在方法上基本一致。而这些都不是重点,重点是通过这种组合 API 的方式,允许我们对数据和方法进行组合的包装,就像这样,我们可以把方法抽离出来单独管理

<template>
  <div>
    <form>
      <input type="text" v-model="state2.stu.id" />
      <input type="text" v-model="state2.stu.name" />
      <input type="text" v-model="state2.stu.age" />
      <input type="submit" @click="addStu" />
    </form>
    <ul>
      <li
        v-for="(sta, index) in state.stus"
        :key="index"
        @click="remStu(index)"
      >
        {{ sta.id }}: {{ sta.name }} -- {{ sta.age }}
      </li>
    </ul>
  </div>
</template>

<script>
import { reactive } from "vue";
export default {
  name: "App",
  // setu函数是组合api的入口函数
  setup() {
  
    let {state,remStu} = removeStu()
    let {state2,addStu} = addStudent(state)
    return { state, remStu, state2, addStu };
  },

  components: {},

  methods: {},
};
// 抽离
// 删除数据
function removeStu() {
  let state = reactive({
    stus: [
      { id: 1, name: "zs", age: 18 },
      { id: 2, name: "ww", age: 1892 },
      { id: 3, name: "ls", age: 120 },
      { id: 4, name: "zz", age: 19 },
    ],
  });
  function remStu(index) {
    state.stus.splice(index, 1);
  }
  return { state, remStu };
}
// 添加数据
function addStudent(state){
    let state2 = reactive({
      stu: {
        id: "",
        name: "",
        age: "",
      },
    });
    function addStu(e) {
      e.preventDefault();
      const stu = Object.assign({}, state2.stu);
      state.stus.push(stu);
      state2.stu.id = "";
      state2.stu.name = "";
      state2.stu.age = "";
    }
    return {state2,addStu}
}
</script>

上面是把方法抽离放到用一个组件里,还可以把方法单独抽离,单独放在js文件中,然后再在组件中引用,用exportimport来进行交流

文件结构长这样

rem.js

import { reactive } from "vue";

// 删除数据
function removeStu() {
    let state = reactive({
        stus: [
            { id: 1, name: "zs", age: 18 },
            { id: 2, name: "ww", age: 1892 },
            { id: 3, name: "ls", age: 120 },
            { id: 4, name: "zz", age: 19 },
        ],
    });
    function remStu(index) {
        state.stus.splice(index, 1);
    }
    return { state, remStu };
}

export default removeStu

add.js

import { reactive } from "vue";

// 添加数据
function addStudent(state) {
    let state2 = reactive({
        stu: {
            id: "",
            name: "",
            age: "",
        },
    });
    function addStu(e) {
        e.preventDefault();
        const stu = Object.assign({}, state2.stu);
        state.stus.push(stu);
        state2.stu.id = "";
        state2.stu.name = "";
        state2.stu.age = "";
    }
    return { state2, addStu }
}
export default addStudent

注意:每个js文件里面都要引入 reactive 方法  import { reactive } from "vue";

  • 作者:随便起的名字也被占用
  • 原文链接:https://csl812.blog.csdn.net/article/details/115635372
    更新时间:2022-08-02 14:45:34