Rumah > hujung hadapan web > View.js > Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!

Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!

藏色散人
Lepaskan: 2022-08-09 09:30:03
ke hadapan
3129 orang telah melayarinya

API Komposisi

  • API Komposisi ialah kemas kini API yang sangat berharga untuk vue3 untuk pembangun kami terlebih dahulu >
1. komposisi vs pilihan

Aplikasi vue yang dibangunkan oleh API pilihan ditunjukkan di sebelah kiri, dan cirinya adalah mudah difahami, kerana setiap pilihan mempunyai kedudukan penulisan tetap. Sebagai contoh, data responsif ditulis dalam pemilihan data, kaedah operasi ditulis dalam item konfigurasi kaedah, dsb. Selepas aplikasi menjadi besar, saya percaya semua orang akan menghadapi dilema mencari kod dari atas dan ke bawah 🎜>Aplikasi vue yang dibangunkan oleh API komposisi ditunjukkan di sebelah kanan Ciri-cirinya ialah segala-galanya yang berkaitan dengan fungsi tertentu disatukan dan diselenggara, seperti data responsif yang berkaitan dengan fungsi A, kaedah data pengendalian, dll. Bersama-sama, tidak kira. betapa besarnya aplikasi, anda boleh membaca dan mencari semua kod yang berkaitan dengan cepat untuk fungsi tertentu, yang mudah diselenggara Jika fungsi itu rumit dan jumlah kodnya besar, kami juga boleh melakukan pemprosesan pemisahan logik [Disyorkan:
    tutorial video vue

  • Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!Nota khas:
    Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!
    API pilihan dan gaya API gabungan wujud bersama Hubungan tidak sama ada/atau
  • Senario yang memerlukan sejumlah besar gabungan logik boleh dipertingkatkan menggunakan API persaingan

  • 2. Perbandingan kes

Di atas kami mempelajari secara ringkas tentang borang API baharu yang dibawa oleh vue3 melalui ilustrasi Seterusnya, kami menggunakan kes kecil khusus untuk mendapatkan pengalaman yang lebih mendalam tentang perbandingan model pembangunan di bawah kedua-dua. API. Mari kita abaikan butiran tatabahasa buat masa ini dan hanya fokus pada bentuk penulisan kod

2.1 Memahami keperluan

Dua fungsi bebas:

Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!
Kawal paparan dan penyembunyian p dengan mengklik butang

  • Kawal perubahan warna fon dalam p dengan mengklik butang

  • 2.2 vue2.x versi Api pilihan

2.3 vue3.0 komposisi versi api

<template>
  <div>
    <!-- 功能一模板 -->
    <button @click="show">显示</button>
    <button @click="hide">隐藏</button>
    <div v-if="showDiv">一个被控制显隐的div</div>
  </div>
  <div>
    <!-- 功能二模板 -->
    <button @click="changeRed">红色</button>
    <button @click="changeYellow">蓝色</button>
    <div :style="`color:${fontColor}`">一个被控制字体颜色的的div</div>
  </div>
</template>

<script>
export default {
  name: &#39;App&#39;,
  data() {
    return {
      showDiv: true, // 功能一数据
      fontColor: &#39;&#39; // 功能二数据
    }
  },
  methods: {
    // 功能一方法
    show() {
      this.showDiv = true
    },
    hide() {
      this.showDiv = false
    },
    // 功能二方法
    changeRed() {
      this.fontColor = &#39;red&#39;
    },
    changeYellow() {
      this.fontColor = &#39;blue&#39;
    }
  }
}
</script>
Salin selepas log masuk
2.4 komposisi api versi pengoptimuman

<template>
  <div>
    <!-- 功能一模板 -->
    <button @click="show">显示</button>
    <button @click="hide">隐藏</button>
    <div v-if="showDivFlag">一个被控制显隐的div</div>
  </div>
  <div>
    <!-- 功能二模板 -->
    <button @click="changeRed">红色</button>
    <button @click="changeBlue">蓝色</button>
    <div :style="`color:${fontColor}`">一个被控制字体颜色的的div</div>
  </div>
</template>

<script>
import { ref } from &#39;vue&#39;
export default {
  name: &#39;App&#39;,
  setup() {
    // 功能一
    const showDivFlag = ref(true)
    function show() {
      showDivFlag.value = true
    }
    function hide() {
      showDivFlag.value = false
    }
    // 功能二

    const fontColor = ref(&#39;&#39;)
    function changeRed() {
      fontColor.value = &#39;red&#39;
    }
    function changeBlue() {
      fontColor.value = &#39;blue&#39;
    }
    return { showDivFlag, show, hide, fontColor, changeRed, changeBlue }
  }
}
</script>
Salin selepas log masuk
Anda mungkin mempunyai keraguan di sini, maka Kami kini mengekalkan semua data dan tingkah laku yang berkaitan dengan fungsi jika aplikasi besar dan mempunyai banyak fungsi, bukankah fungsi persediaan akan menjadi sangat besar? Bukankah ia akan menjadi lebih sukar untuk dikekalkan? Seterusnya, mari kita hapuskan fungsi persediaan yang besar

Di atas, kami menentukan fungsi berfungsi untuk memisahkan dua kod yang berkaitan dengan fungsian fungsi, dan kemudian menggabungkan dua fungsi fungsi kecil dalam fungsi setUp Dengan cara ini, kita bukan sahaja boleh menjadikan fungsi persediaan menyegarkan, tetapi juga memudahkan penyelenggaraan fungsi kedudukan pantas

<script>import { ref } from &#39;vue&#39;function useShow() {
  const showpFlag = ref(true)
  function show() {
    showpFlag.value = true
  }
  function hide() {
    showpFlag.value = false
  }
  return { showpFlag, show, hide }}function useColor() {
  const fontColor = ref(&#39;&#39;)
  function changeRed() {
    fontColor.value = &#39;red&#39;
  }
  function changeBlue() {
    fontColor.value = &#39;blue&#39;
  }
  return { fontColor, changeRed, changeBlue }}export default {
  name: &#39;App&#39;,
  setup() {
    // 功能一
    const { showpFlag, show, hide } = useShow()
    // 功能二
    const { fontColor, changeRed, changeBlue } = useColor()
    return { showpFlag, show, hide, fontColor, changeRed, changeBlue }
  }}</script>
Salin selepas log masuk
Sehingga ini. Kami tidak memberi perhatian kepada butiran API, tetapi baru menyedari faedah yang telah diberikan oleh gabungan API. Seterusnya kami akan pergi ke butiran API dan melihat cara menggunakan API baharu↓

< 🎜. >

3. Fungsi kemasukan Persediaan

Fungsi persediaan ialah pilihan komponen baharu, yang berfungsi sebagai titik permulaan (masuk) gabungan API dalam komponen

Ini tidak boleh digunakan dalam persediaan , ini menunjukkan kepada undefined

    Fungsi persediaan hanya akan dilaksanakan sekali apabila komponen dimulakan
  1. Fungsi persediaan dilaksanakan sebelum cangkuk sebelumCreate kitaran hayat dilaksanakan
  2. 4 . API sistem reaktif
  3. 4.1 fungsi reaktif
export default {
  setup () {
    console.log(&#39;setup执行了&#39;)
    console.log(this)
  },
  beforeCreate() {
    console.log(&#39;beforeCreate执行了&#39;)
    console.log(this)
  }}
Salin selepas log masuk

Fungsi: reaktif ialah fungsi yang menerima objek biasa yang dihantar, menukar data objek kepada objek responsif dan Kembali

    Gunakan langkah
untuk mengimport fungsi reaktif daripada rangka kerja vue

  • dalam fungsi persediaan Panggil fungsi reaktif dan hantar data objek ke dalam

  • Dalam fungsi persediaan, kembalikan nilai pulangan selepas fungsi reaktif dipanggil masuk bentuk objek

  • Pelaksanaan kod

  • 4.2 fungsi ref

<template>
  <div>{{ state.name }}</div>
  <div>{{ state.age }}</div>
  <button @click="state.name = &#39;pink&#39;">改值</button>
</template>

<script>
import { reactive } from &#39;vue&#39;
export default {
  setup () {
    const state = reactive({
      name: &#39;cp&#39;,
      age: 18
    })
    return {
      state
    }
  }
}
</script>
Salin selepas log masuk
Fungsi: ref ialah fungsi yang menerima jenis ringkas atau kompleks dan mengembalikan respons Dan objek ref berubah

    menggunakan langkah
untuk mengeksport fungsi ref daripada vue rangka kerja

  • Panggil fungsi ref dalam fungsi persediaan dan hantarkan data (jenis ringkas atau jenis kompleks)

  • Dalam fungsi persediaan, kembalikan nilai pulangan fungsi ref dalam bentuk objek

  • Nota: Apabila menggunakan hasil ref dalam fungsi persediaan, anda perlu mengaksesnya melalui .value dalam templat, anda tidak perlu menambah .value

  • Ringkasan:

<template>
  <div>{{ money }}</div>
  <button @click="changeMondy">改值</button>
</template>

<script>
import { ref } from &#39;vue&#39;
export default {
  setup() {
    let money = ref(100)
    console.log(money.value)
    return {
      money
    }
  }
}
</script>
Salin selepas log masuk
Fungsi ref boleh menerima nilai jenis mudah dan kembalikan objek ref responsif yang boleh diubah, dengan itu menebus masalah bahawa fungsi reaktif tidak menyokong jenis mudah

  • reactive和ref函数都可以提供响应式数据的转换,具体什么时候需要使用哪个API社区还没有最佳实践,大家暂时可以使用自己熟练的API进行转换

  • 推荐一种写法:只有我们明确知道要转换的对象内部的字段名称我们才使用reactive,否则就一律使用ref,从而降低在语法选择上的心智负担

  • 4.3 toRefs 函数

    • 场景: 经过reactive函数处理之后返回的对象,如果给这个对象解构或者展开,会让数据丢失响应式的能力,为了解决这个问题需要引入toRefs函数,使用 toRefs函数 可以保证该对象展开的每个属性都是响应式的

    4.3.1 问题复现

    还是之前的案例,如果我们想在模板中省略到state,直接书写name和age,你可能会想到,那我在return出去的时候把state中的属性解构出来不就好了

    修改前

    <template>
      <div>{{ state.name }}</div>
      <div>{{ state.age }}</div>
      <button @click="state.name = &#39;pink&#39;">改值</button>
    </template>
    
    <script>
    import { reactive } from &#39;vue&#39;
    export default {
      setup() {
        const state = reactive({
          name: &#39;cp&#39;,
          age: 18
        })
        return {
          state
        }
      }
    }
    </script>
    Salin selepas log masuk

    解构修改后

    <template>
      <div>{{ name }}</div>
      <div>{{ age }}</div>
      <button @click="name = &#39;pink&#39;">改值</button>
    </template>
    <script>
    import { reactive } from &#39;vue&#39;
    export default {
      setup() {
        const state = reactive({
          name: &#39;cp&#39;,
          age: 18
        })
        return {
          ...state
        }
      }
    }
    </script>
    Salin selepas log masuk
    • 点击改值按钮,发现视图已经不发生变化了,这就是我们所说的,如果解构reactive的返回值,将破坏调用响应式特性,就需要我们使用toRefs方法进行处理了

    4.3.2 toRefs包裹处理

    <template>
      <div>{{ name }}</div>
      <div>{{ age }}</div>
      <button @click="name = &#39;pink&#39;">改值</button>
    </template>
    
    <script>
    import { reactive,toRefs } from &#39;vue&#39;
    export default {
      setup() {
        const state = reactive({
          name: &#39;cp&#39;,
          age: 18
        })
        return {
          ...toRefs(state)
        }
      }
    }
    </script>
    Salin selepas log masuk

    4.4 computed

    • 在setup函数中使用计算属性函数

    作用:根据现有响应式数据经过一定的计算得到全新的数据

    使用步骤

    • 从vue框架中导入computed 函数

    • 在setup函数中执行computed函数,并传入一个函数,在函数中定义计算公式

    • 把computed函数调用完的执行结果放到setup的return值对象中

    <template>
      {{ list }}
      {{ filterList }}  <button @click="changeList">change list</button></template><script>import { computed, ref } from &#39;vue&#39;export default {
      setup() {
        const list = ref([1, 2, 3, 4, 5])
        // 输入大于3的数字
        const filterList = computed(() => {
          return list.value.filter(item => item > 3)
        })
        // 修改list的函数
        function changeList() {
          list.value.push(6, 7, 8)
        }
        return {
          list,
          filterList,
          changeList    }
      }}</script>
    Salin selepas log masuk

    4.5 watch 侦听器

    • 在setup函数中侦听器的使用

    作用:基于响应式数据的变化执行回调逻辑,和vue2中的watch的功能完全一致

    • 普通监听

    • 立即执行

    • 深度监听

    使用步骤

    • 从vue框架中导入watch函数

    • 在setup函数中执行watch函数开启对响应式数据的监听

    • watch函数接收三个常规参数

      1. 第一个参数为函数,返回你要监听变化的响应式数据
      2. 第二个参数为响应式数据变化之后要执行的回调函数
      3. 第三个参数为一个对象,在里面配置是否开启立刻执行或者深度监听

    4.5.1 普通监听

    <template>
      {{ age }}  <button @click="age++">change age</button></template><script>import { ref, watch } from &#39;vue&#39;export default {
      setup() {
        const age = ref(18)
        watch(() => {
          // 返回你想要监听的响应式属性(ref产生的对象必须加.value)
          return age.value    }, () => {
          // 数据变化之后的回调函数
          console.log(&#39;age发生了变化&#39;)
        })
        return {
          age    }
      }}</script>
    Salin selepas log masuk

    4.5.2 开启立刻执行

    watch的效果默认状态下,只有监听的数据发生变化才会执行回调,如果你需要在一上来的时候就立刻执行一次,需要配置一下immediate属性

    <template>
      {{ age }}  <button @click="age++">change age</button></template><script>import { ref, watch } from &#39;vue&#39;export default {
      setup() {
        const age = ref(18)
        watch(() => {
          // 返回你想要监听的响应式属性(ref产生的对象必须加.value)
          return age.value    }, () => {
          // 数据变化之后的回调函数
          console.log(&#39;age发生了变化&#39;)
        },{ immediate: true})
        return {
          age    }
      }}</script>
    Salin selepas log masuk

    4.5.3 开启深度监听

    当我们监听的数据是一个对象的时候,默认状态下,对象内部的属性发生变化是不会引起回调函数执行的,如果想让对象下面所有属性都能得到监听,需要开启deep配置

    <template>
      {{ name }}
      {{ info.age }}  <button @click="name = &#39;pink&#39;">change name</button>
      <button @click="info.age++">change age</button></template><script>import { reactive, toRefs, watch } from &#39;vue&#39;export default {
      setup() {
        const state = reactive({
          name: &#39;cp&#39;,
          info: {
            age: 18
          }
        })
        watch(() => {
          return state    }, () => {
          // 数据变化之后的回调函数
          console.log(&#39;age发生了变化&#39;)
        }, {
          deep: true
        })
        return {
          ...toRefs(state)
        }
      }}</script>
    Salin selepas log masuk

    4.5.4 更好的做法

    使用watch的时候,尽量详细的表明你到底要监听哪个属性,避免使用deep引起的性能问题,比如我仅仅只是想在state对象的age属性变化的时候执行回调,可以这么写

    <template>
      {{ name }}
      {{ info.age }}  <button @click="name = &#39;pink&#39;">change name</button>
      <button @click="info.age++">change age</button></template><script>import { reactive, toRefs, watch } from &#39;vue&#39;export default {
      setup() {
        const state = reactive({
          name: &#39;cp&#39;,
          info: {
            age: 18
          }
        })
        watch(() => {
          // 详细的告知你要监听谁
          return state.info.age    }, () => {
          // 数据变化之后的回调函数
          console.log(&#39;age发生了变化&#39;)
        })
        return {
          ...toRefs(state)
        }
      }}</script>
    Salin selepas log masuk

    5. 生命周期函数

    使用步骤

    • 先从vue中导入以on打头的生命周期钩子函数

    • 在setup函数中调用生命周期函数并传入回调函数

    • 生命周期钩子函数可以调用多次

    <template>
      <div>生命周期函数</div>
    </template>
    
    <script>
    import { onMounted } from &#39;vue&#39;
    export default {
      setup() {
        // 时机成熟 回调函数自动执行
        onMounted(() => {
          console.log(&#39;mouted生命周期执行了&#39;)
        })
         onMounted(() => {
          console.log(&#39;mouted生命周期函数又执行了&#39;)
        })
      }
    }
    </script>
    Salin selepas log masuk
    选项式API组合式API
    beforeCreate不需要(直接写到setup函数中)
    created不需要(直接写到setup函数中)
    beforeMountonBeforeMount
    mountedonMounted
    beforeUpdateonBeforeUpdate
    updatedonUpdated
    beforeDestroyedonBeforeUnmount
    destroyedonUnmounted

    6. 父子通信

    在vue3的组合式API中,父传子的基础套路完全一样,基础思想依旧为:父传子是通过prop进行传入,子传父通过调用自定义事件完成

    实现步骤

    • setup函数提供俩个参数,第一个参数为props,第二个参数为一个对象context

    • props为一个对象,内部包含了父组件传递过来的所有prop数据,context对象包含了attrs,slots, emit属性,其中的emit可以触发自定义事件的执行从而完成子传父

    代码落地
    app.vue

    <template>
      <son :name="name" @get-msg="getMsg"></son></template><script>import { ref } from &#39;vue&#39;import Son from &#39;./components/son&#39;export default {
      components: {
        Son  },
      setup() {
        const name = ref(&#39;cp&#39;)
        function getMsg(msg) {
          console.log(msg)
        }
        return {
          name,
          getMsg    }
      }}</script>
    Salin selepas log masuk

    components/son.vue

    <template>
      <div>
        {{name}}
        <button @click="setMsgToSon">set</button>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        name: {
          type: String
        }
      },
      emits: [&#39;get-msg&#39;], // 声明当前组件触发的自定义事件
      setup(props,{emit}) {
        console.log(props.name)
        function setMsgToSon(){
          emit(&#39;get-msg&#39;,&#39;这是一条来自子组件的msg信息&#39;)
        }
        return {
          setMsgToSon
        }
      }
    }
    </script>
    Salin selepas log masuk

    7. provide 和 inject

    通常我们使用props进行父子之间的数据传递,但是如果组件嵌套层级较深,一层一层往下传递将会变的非常繁琐,有没有一种手段可以把这个过程简化一下呢,有的,就是我们马上要学习的provide 和 inject,它们配合起来可以方便的完成跨层传递数据

    Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!

    7.1 基础使用

    • 在setup函数中使用provide和inject的基础用法

    来个需求: 爷组件中有一份数据 传递给孙组件直接使用
    Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!

    实现步骤:

    • 顶层组件在setup方法中使用provide函数提供数据

    • 任何底层组件在setup方法中使用inject函数获取数据

    代码落地
    爷爷组件 - app.vue

    <template>
      <father></father></template><script>import Father from &#39;@/components/Father&#39;import { provide } from &#39;vue&#39;export default {
      components: {
        Father  },
      setup() {
        let name = &#39;柴柴老师&#39;
        // 使用provide配置项注入数据 key - value
        provide(&#39;name&#39;, name)
      }}</script>
    Salin selepas log masuk

    孙组件 - components/Son.vue

    <template>
      我是子组件
      {{ name }}</template><script>import { inject } from &#39;vue&#39;export default {
      setup() {
        const name = inject(&#39;name&#39;)
        return {
          name    }
      }}</script>
    Salin selepas log masuk

    事实上,只要是后代组件,都可以方便的获取顶层组件提供的数据

    7.2 传递响应式数据

    provide默认情况下传递的数据不是响应式的,也就是如果对provide提供的数据进行修改,并不能响应式的影响到底层组件使用数据的地方,如果想要传递响应数据也非常简单,只需要将传递的数据使用ref或者reactive生成即可

    • 通过provide/inject传递响应式数据
      app.vue
    <template>
      <father></father>
      <button @click="changeName">change name</button></template><script>import Father from &#39;@/components/Father&#39;import { provide, ref } from &#39;vue&#39;export default {
      components: {
        Father  },
      setup() {
        // 使用ref转换成响应式再传递
        let name = ref(&#39;柴柴老师&#39;)
        function changeName(){
          name.value = &#39;pink&#39;
        }
        provide(&#39;name&#39;, name)
        return {
          changeName    }
      }}</script>
    Salin selepas log masuk

    8. 模板中 ref 的使用

    在模板中使用ref,我们都很清楚,它一般有三种使用场景

    • ref + 普通dom标签 获取真实dom对象

    • ref + 组件标签 获取组件实例对象

    • ref + v-for 获取由dom对象(实例对象)组成的数组 (不经常使用)

    • 在setup函数中使用ref获取真实dom获取组件实例的方法

    实现步骤

    • 使用ref函数传入null创建 ref对象 => const hRef = ref(null)

    • 模板中通过定义ref属性等于1中创建的ref对象名称建立关联 => <h1 ref="hRef"></h1>

    • 使用 =>hRef.value

    代码落地
    components/RefComponent.vue

    <template>
      我是一个普通的组件</template>
    Salin selepas log masuk

    app.vue

    <template>
      <h1 ref="h1Ref">我是普通dom标签</h1>
      <ref-comoonent ref="comRef"></ref-comoonent></template><script>import { onMounted, ref } from &#39;vue&#39;import RefComoonent from &#39;@/components/RefComponent&#39;export default {
      components: {
        RefComoonent  },
      setup() {
        const h1Ref = ref(null)
        const comRef = ref(null)
        onMounted(() => {
          console.log(h1Ref.value)
          console.log(comRef.value)
        })
        // 必须return
        return {
          h1Ref,
          comRef    }
      }}</script>
    Salin selepas log masuk

    9. 来个案例吧 - Todos

    核心功能

    • 渲染列表数据 v-for

    • 点击删除当前列表 splice + index

    • 回车添加新项目 @keyup.enter=“addTodo” list.unshift

    • 选择状态切换 v-model

    • 多选和取消多选 计算属性的set和get

    • 未完成任务数量统计 computed

    <template>
      <section class="todoapp">
        <!-- 头部输入框区域 -->
        <header class="header">
          <h1>todos</h1>
          <input
            class="new-todo"
            placeholder="请输入要完成的任务"
            autofocus
            v-model="curTask"
            @keyup.enter="add"
          />
        </header>
        <section class="main">
          <!-- 全选切换input -->
          <input id="toggle-all" class="toggle-all" type="checkbox" v-model="isAll"/>
          <label for="toggle-all">标记所有已经完成</label>
          <ul class="todo-list">
            <!-- 任务列表 -->
            <li v-for="(item, index) in list" :key="item.id">
              <p class="view">
                <!-- 双向绑定 flag -->
                <input class="toggle" type="checkbox" v-model="item.flag" />
                <label>{{ item.name }}</label>
                <!-- 删除按钮 -->
                <button class="destroy" @click="del(index)"></button>
              </p>
            </li>
          </ul>
        </section>
        <footer class="footer">
          <span class="todo-count"> 还未完成的任务有:<strong>{{count}}</strong>项 </span>
        </footer>
      </section></template><script>import { computed, ref } from &#39;vue&#39;export default {
      setup() {
        const list = ref([
          { id: 1, name: &#39;吃饭&#39;, flag: false },
          { id: 2, name: &#39;睡觉&#39;, flag: false },
          { id: 3, name: &#39;打豆豆&#39;, flag: true }
        ])
    
        // 删除函数
        function del(index) {
          // index 要删除项的下标值
          // splice
          list.value.splice(index, 1)
        }
    
        const curTask = ref(&#39;&#39;)
        function add() {
          // 添加逻辑
          list.value.unshift({
            id: new Date(),
            name: curTask.value,
            flag: false
          })
          curTask.value = &#39;&#39;
        }
    
        // 全选取消全选
        // {name:"cp"}  console.log(info.name)  info.name = &#39;pink&#39;
        const isAll = computed({
          // 获取isAll数据的时候会执行get函数
          get() {
            // 当list列表中所有项的flag属性都为true 就为true
            // every
            return list.value.every(item => item.flag === true)
          },
          set(val) {
            // 拿到isAll最新值 遍历一下list 把里面的flag属性设置为最新值
            list.value.forEach(item => {
              item.flag = val        })
          }
        })
    
        // 计算未完成的任务
        const count = computed(()=>{
          return  list.value.filter(item=>item.flag === false).length    })
       
        return {
          list,
          del,
          curTask,
          add,
          isAll,
          count    }
      }}</script><style>html,
    body {
      margin: 0;
      padding: 0;}button {
      margin: 0;
      padding: 0;
      border: 0;
      background: none;
      font-size: 100%;
      vertical-align: baseline;
      font-family: inherit;
      font-weight: inherit;
      color: inherit;
      -webkit-appearance: none;
      appearance: none;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;}body {
      font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
      line-height: 1.4em;
      background: #f5f5f5;
      color: #111111;
      min-width: 230px;
      max-width: 550px;
      margin: 0 auto;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      font-weight: 300;}:focus {
      outline: 0;}.hidden {
      display: none;}.todoapp {
      background: #fff;
      margin: 130px 0 40px 0;
      position: relative;
      box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);}.todoapp input::-webkit-input-placeholder {
      font-style: italic;
      font-weight: 300;
      color: rgba(0, 0, 0, 0.4);}.todoapp input::-moz-placeholder {
      font-style: italic;
      font-weight: 300;
      color: rgba(0, 0, 0, 0.4);}.todoapp input::input-placeholder {
      font-style: italic;
      font-weight: 300;
      color: rgba(0, 0, 0, 0.4);}.todoapp h1 {
      position: absolute;
      top: -140px;
      width: 100%;
      font-size: 80px;
      font-weight: 200;
      text-align: center;
      color: #b83f45;
      -webkit-text-rendering: optimizeLegibility;
      -moz-text-rendering: optimizeLegibility;
      text-rendering: optimizeLegibility;}.new-todo,
    .edit {
      position: relative;
      margin: 0;
      width: 100%;
      font-size: 24px;
      font-family: inherit;
      font-weight: inherit;
      line-height: 1.4em;
      color: inherit;
      padding: 6px;
      border: 1px solid #999;
      box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
      box-sizing: border-box;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;}.new-todo {
      padding: 16px 16px 16px 60px;
      border: none;
      background: rgba(0, 0, 0, 0.003);
      box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);}.main {
      position: relative;
      z-index: 2;
      border-top: 1px solid #e6e6e6;}.toggle-all {
      width: 1px;
      height: 1px;
      border: none; /* Mobile Safari */
      opacity: 0;
      position: absolute;
      right: 100%;
      bottom: 100%;}.toggle-all + label {
      width: 60px;
      height: 34px;
      font-size: 0;
      position: absolute;
      top: -52px;
      left: -13px;
      -webkit-transform: rotate(90deg);
      transform: rotate(90deg);}.toggle-all + label:before {
      content: "❯";
      font-size: 22px;
      color: #e6e6e6;
      padding: 10px 27px 10px 27px;}.toggle-all:checked + label:before {
      color: #737373;}.todo-list {
      margin: 0;
      padding: 0;
      list-style: none;}.todo-list li {
      position: relative;
      font-size: 24px;
      border-bottom: 1px solid #ededed;}.todo-list li:last-child {
      border-bottom: none;}.todo-list li.editing {
      border-bottom: none;
      padding: 0;}.todo-list li.editing .edit {
      display: block;
      width: calc(100% - 43px);
      padding: 12px 16px;
      margin: 0 0 0 43px;}.todo-list li.editing .view {
      display: none;}.todo-list li .toggle {
      text-align: center;
      width: 40px;
      /* auto, since non-WebKit browsers doesn&#39;t support input styling */
      height: auto;
      position: absolute;
      top: 0;
      bottom: 0;
      margin: auto 0;
      border: none; /* Mobile Safari */
      -webkit-appearance: none;
      appearance: none;}.todo-list li .toggle {
      opacity: 0;}.todo-list li .toggle + label {
      background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-position: center left;}.todo-list li .toggle:checked + label {
      background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E");}.todo-list li label {
      word-break: break-all;
      padding: 15px 15px 15px 60px;
      display: block;
      line-height: 1.2;
      transition: color 0.4s;
      font-weight: 400;
      color: #4d4d4d;}.todo-list li.completed label {
      color: #cdcdcd;
      text-decoration: line-through;}.todo-list li .destroy {
      display: none;
      position: absolute;
      top: 0;
      right: 10px;
      bottom: 0;
      width: 40px;
      height: 40px;
      margin: auto 0;
      font-size: 30px;
      color: #cc9a9a;
      margin-bottom: 11px;
      transition: color 0.2s ease-out;}.todo-list li .destroy:hover {
      color: #af5b5e;}.todo-list li .destroy:after {
      content: "×";}.todo-list li:hover .destroy {
      display: block;}.todo-list li .edit {
      display: none;}.todo-list li.editing:last-child {
      margin-bottom: -1px;}.footer {
      padding: 10px 15px;
      height: 20px;
      text-align: center;
      font-size: 15px;
      border-top: 1px solid #e6e6e6;}.footer:before {
      content: "";
      position: absolute;
      right: 0;
      bottom: 0;
      left: 0;
      height: 50px;
      overflow: hidden;
      box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,
        0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,
        0 17px 2px -6px rgba(0, 0, 0, 0.2);}.todo-count {
      float: left;
      text-align: left;}.todo-count strong {
      font-weight: 300;}.filters {
      margin: 0;
      padding: 0;
      list-style: none;
      position: absolute;
      right: 0;
      left: 0;}.filters li {
      display: inline;}.filters li a {
      color: inherit;
      margin: 3px;
      padding: 3px 7px;
      text-decoration: none;
      border: 1px solid transparent;
      border-radius: 3px;}.filters li a:hover {
      border-color: rgba(175, 47, 47, 0.1);}.filters li a.selected {
      border-color: rgba(175, 47, 47, 0.2);}.clear-completed,
    html .clear-completed:active {
      float: right;
      position: relative;
      line-height: 20px;
      text-decoration: none;
      cursor: pointer;}.clear-completed:hover {
      text-decoration: underline;}.info {
      margin: 65px auto 0;
      color: #4d4d4d;
      font-size: 11px;
      text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
      text-align: center;}.info p {
      line-height: 1;}.info a {
      color: inherit;
      text-decoration: none;
      font-weight: 400;}.info a:hover {
      text-decoration: underline;}/*
    	Hack to remove background from Mobile Safari.
    	Can&#39;t use it globally since it destroys checkboxes in Firefox
    */@media screen and (-webkit-min-device-pixel-ratio: 0) {
      .toggle-all,
      .todo-list li .toggle {
        background: none;
      }
    
      .todo-list li .toggle {
        height: 40px;
      }}@media (max-width: 430px) {
      .footer {
        height: 50px;
      }
    
      .filters {
        bottom: 10px;
      }}</style>
    Salin selepas log masuk

    Atas ialah kandungan terperinci Sangat terperinci! Grafik dan teks menerangkan gabungan API Vue3!. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

    Label berkaitan:
    vue
    sumber:csdn.net
    Kenyataan Laman Web ini
    Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
    Tutorial Popular
    Lagi>
    Muat turun terkini
    Lagi>
    kesan web
    Kod sumber laman web
    Bahan laman web
    Templat hujung hadapan