1. 程式人生 > 實用技巧 >邏輯分離和複用

邏輯分離和複用

Vue 2.x 程式碼寫法

<template>
      <div class="search">
            <form>
                  <input v-model="searchValue" type="text" />
                  <button @click="search"></button>
            </form>
      </div>
      <ul class="result">
            <li class="result__item" v-for="item in filterData" :key="item.id">
                  {{ item.name }}
            </li>
      </ul>
      <span v-if="loading">Loading</span>
</template>
<script>
export default {
      data() {
            searchValue: '',
            loading: true,
            searchResult: []
      },
      computed: {
            filterData() {
                  return searchResult.filter(i => i.id > 3)
            }
      },
      methods: {
            async search() {
                  this.loading = true
                  const { data } = await fetch('/search', body: this.searchValue.trim())
                  this.searchResult = data.toJSON()
                  this.loading = false
            }
      },
      mounted() {
            this.search()
      }
}
</script>

使用 Composition API 下工作的程式碼

明顯變化:

  1. 元件從原本的選項配置變成了函式定義
  2. 元件也不需要使用 this 去指定當前元件執行的上下文
<template>
      <div class="search">
            <form>
                  <input v-model="state.searchValue" type="text" />
                  <button @click="search"></button>
            </form>
            <ul class="result">
                  <li class="result__item" v-for="item in filterData" :key="item.id">
                        {{ item.name }}
                  </li>
            </ul>
            <span v-if="state.loading">Loading</span>
      </div>
</template>
<script>
import { reactive, computed, onMounted, toRef } from '@vue/composition-api'

export default {
      setup() {
            // 初始化資料
            const state = reactive({
                  searchValue: '',
                  loading: true,
                  searchResult: []
            })
		
            const filterData = computed(() => state.searchResult.filter(i => i.id > 3))
		
            async function search() {
                  state.loading = true
                  const { data } = await fetch('/search', body: this.searchValue.trim())
                  state.searchResult = data.toJSON()
                  state.loading = false
            }
		
            onMounted(() => {
                  search()
            })
            return { ...toRef(state), filterData, search }
      }
}
</script>

邏輯分離和複用

<script>
import { reactive, computed, onMounted, toRef, ref } from '@vue/composition-api'
// 方法提取
function useSearch() {
      const searchValue = ref('')
      const searchResult = ref([])
      const loading = ref(true)
	
      async function search() {
            loading.value = true
            const { data } = await fetch('/search', body: searchValue.trim())
            searchResult.value = data.toJSON()
            loading.value = false
      }
	
      onMounted(() => search())
	
      return { searchValue, searchResult, loading, search }
}

// 提取計算屬性
function useFilterSearchResult(searchResult) {
      const filterData = computed(() => searchResult.value.filter(I=》 i.id > 3))
      return { filterData }
}

export default {
      setup(props, context) {
            const search = useSearch()
            return { 
                  ...search, 
                  ...useFilterSearchResult(search.searchResult)
            }
      }
}
</script>

缺點 (資料無響應情況)

當state作為一個返回值引數的時候,它實際是作為一個值傳遞到了另外一個方法中,所以getter、setter將會丟失,資料無法響應。引用傳遞及值傳遞

function useMounsePosition(){
      const pos = reactive({
            x: 0,
            y: 0
      })
      onMount(() => {})
      return pos
}
# 資料響應丟失清空
export default {
      setup() {
            // 這裡只取了 useMousePosition 返回值的引用值
            // 而值裡面的 getter / setter 丟失
            const { x, y } = useMousePosition()
            // 響應丟失
            return { x, y }
		
            // 響應丟失
            return { ...useMousePosition() }
		
            // 可以工作
            return {
                  pos: useMousePosition()
            }
      }
}

解決方案一 使用 toRefs

function useMounsePosition(){
      const pos = reactive({
            x: 0,
            y: 0
      })
      onMount(() => {})
      return toRefs(pos)
}
export default {
      setup() {
            // 正確
            const { x, y } = useMousePosition()
            return { x, y }
	     
            // 正確
            return { ...useMousePosition() }
      }
}

解決方案二 使用 ref去初始資料

unction useMounsePosition(){
      const x = ref(0)
      const y = ref(0)
	
      onMount(() => {
            document.body.addeventListener("mousemove", (e) => {
                  x.value = e.x
		  y.value = e.y
            })
      })
      return { x, y }
}
export default {
      setup() {
            // 正確
            const { x, y } = useMousePosition()
            return { x, y }
	
            // 正確
            return { ...useMousePosition() }
      }
}