vue3程式碼編寫

前端訂閱發表於2022-07-16

vue3程式碼編寫

團隊內的vue3已經升級一年,在這一年中vue也在不停的更新,為了最大化組合式api帶來的優勢,便需要合理規範程式碼的編寫方式…

1.從vue2到vue3

  • vue2元件採用配置式API,導致同樣的功能塊分散,並和其他的功能塊混合。我們希望統一功能塊的程式碼可以放在(封裝)一起,在空間上增加可讀性:

  • 總的來說,就是將一個大型的vue2程式碼塊變成許多小型的vue2塊:

假設一個頁面中有三個功能模組,分別是A,B,C,那麼一下就是寫法上的不同

1// vue2
2
3export default {
4  data() {
5    return {
6      dataA: dataA,
7      dataB: dataB,
8      dataC: dataC
9    }
10  },
11  computed: {
12    computedA() {
13      return dataA
14    },
15    computedB() {
16      return dataB
17    },
18    computedC() {
19      return dataC
20    }
21  },
22  mounted() {
23    this.methodA()
24    this.methodB()
25    this.methodC()
26  },
27  methods: {
28    async methodA() {
29      console.log(computedA)
30    },
31    async methodB() {
32      console.log(computedB)
33    },
34    async methodC() {
35      console.log(computedC)
36    }
37  }
38}
39
40// vue3
41
42export default {
43  setup() {
44    // A
45    const dataA = ref()
46    const computedA = computed(() => {
47      return dataA.value
48    })
49    const methodA = () => {
50      console.log(computedA.value)
51    }
52    onMounted(() => {
53      methodA()
54    })
55
56    // B
57    const dataB = ref()
58    const computedB = computed(() => {
59      return dataB.value
60    })
61    const methodB = () => {
62      console.log(computedB.value)
63    }
64    onMounted(() => {
65      methodB()
66    })
67
68
69    // C
70    const dataC = ref()
71    const computedC = computed(() => {
72      return dataC.value
73    })
74    const methodC = () => {
75      console.log(computedC.value)
76    }
77    onMounted(() => {
78      methodC()
79    })
80
81    return {
82      dataA: dataA,
83      computedA,
84      methodA,
85      dataB: dataB,
86      computedB,
87      methodB,
88      dataC: dataC
89      computedC,
90      methodC,
91    }
92  }
93}

可以看到原來只能在vue2中配置一次的屬性(computed等),setup中可以多次呼叫,從而實現了同一功能程式碼的整合,並且你還可以將某些可複用的攜帶vueApi的程式碼封裝:

1// C.js
2export default () => {
3  const dataC = ref()
4  const computedC = computed(() => {
5    return dataC.value
6  })
7  const methodC = () => {
8    console.log(computedC.value)
9  }
10  onMounted(() => {
11    methodC()
12  })
13
14  return {
15    dataC: dataC
16    computedC,
17    methodC
18  }
19}
20
21// 呼叫
22import C from 'c.js'
23
24const c = C()

2. 程式碼編寫優化

如上,我們已經不需要上下滾動編輯器以除錯程式碼了,但是有兩個問題希望可以解決。一個是寫法上更加靈活了也會導致混亂的問題,如果沒有遵循一定的規範,則程式碼會變成程式導向似的結構,一篇到底;第二個是每個需要在模板中使用的變數與方法都需要收到return,相對麻煩

  • 藉助reactive和toRefs,重新規整程式碼
1export default {
2  setup() {
3    // A
4    const A = reactive({
5      dataA: dataA,
6      computedA: computed(() => {
7        return dataA.value
8      }),
9      methodA() {
10        console.log(computedA.value)
11      }
12    })
13    onMounted(() => {
14      A.methodA()
15    })
16
17    // B
18    const B = reactive({
19      dataB: dataB,
20      computedB: computed(() => {
21        return dataB.value
22      }),
23      methodB() {
24        console.log(computedB.value)
25      }
26    })
27    onMounted(() => {
28      B.methodB()
29    })
30
31    return {
32      ...toRefs(A),
33      ...toRefs(B)
34    }
35  }
36}

這樣寫的好處在於,同一塊的功能被包裹在一個reactive中相對獨立(當然不同模組之間可以相互呼叫),程式碼結構更加的清晰,而且只需return整個模組,模組中新增的變數會自動匯出在模板中可用

3. setup語法糖的發展

1. css變數

vue提出在單檔案中使用當前例項的變數

1<script>
2export default {
3  setup () {
4    return {
5      opacity0,
6      font: {
7      weight100
8      }
9    }
10  }
11}
12
</script>
13
14<style>
15div {
16  opacityv-bind(opacity);
17  font-weightv-bind('font.weight');
18}
19
</style>

在此語法糖之前,想通過變數修改樣式都需要通過在模板中直接繫結樣式物件或者以修改類名的方式來實現,現在可以直接使用css樣式變數了,不得不說是個很奈斯的語法糖

2. <script setup>和ref文件

vue提出在單檔案元件中引入<script setup>的型別,可以自動將所有頂級變數宣告暴露給模板使用,同時可以消除ref.value的寫法

1<script setup>
2// 引入的 Foo 元件可以直接在 template 裡使用了!
3import Foo from './Foo.vue'
4// 就像在普通的 setup() 中一樣編寫程式碼,無須return變數
5ref: a = 1
6// 該變數可以像普通變數那樣使用
7console.log(a++)
8// 想要獲取到原本的變數的話需要在變數前面加一個?符號
9console.log($count.value)
10const fn = () => {}
11<script>

至此許多具有爭議的論點被廣大開發者提出:
從寫法上,確實實使得程式碼更加的簡潔,減少了元件宣告以及手動暴露變數的程式碼,這也是編者比較認可的,但是確實帶來不少的問題

  • 根據文件中提出,部分情況還是隻能使用普通的<script>標籤,如:

    • 部分選項(inheritAttrs)無法宣告
    • 宣告只需要執行一次的程式碼
    • 不支援使用render函式
  • 無法像普通的<script>標籤那樣只暴露部分變數,暴露所有變數必將導致生成的程式碼變大,而暴露變數的問題,上面我們已經用toRefs解決大部分問題,相比之下,反而會產生下面的問題:

1<script setup>
2const data = reactive({
3  a1,
4  b2
5})
6// 因為語法糖自動暴露data,而模板中使用a變數的時候需要寫data.a,多了一層
7
8// 如果想在模板中直接使用a變數,則需要解構:
9const { a, b } = ...toRefs(data)
10// 這樣又變成,每新增一個變數都要手動解構,與最開始的return無異,而且還要寫a.value
11
12// 如果想規避這個問題就不能使用reactive,則每個基礎資料都必須使用ref
13const a = ref(1)
14ref: b = 2
15// 這樣一來,又分散了程式碼,產生了ref.value的問題
16<script>
  • 針對ref的語法糖,已經不在是javascript了,原來的vue正因為是逐漸式的框架帶來的便利,甚至於所寫的程式碼可以直接在瀏覽器中執行(只要引入vue.js),而這樣的創新語法(至少對於vue來說),則只能存在於編譯之前,一時難以接受,並且遭到大家的反對。

  • 有一就有二,如果維持這樣的創新,那麼將來大家寫的就不再是js,而是被vue‘挾持’的js了。況且這些語法糖只能在setup語法糖中使用,不利於封裝

總之大家的看法各異,在程式碼編寫上必將產生不同的選擇,編者也擔心vue生態或許會分散,從而解決問題的效率變低

3. 新的ref文件

因為以上提出的各種原因,以及社群開發者的反對意見,舊的ref語法糖最終還是被廢棄,而新的ref語法糖重新進入實驗

1<script setup>
2// 在setup語法糖中引入了全域性變數$ref,直接使用可以不寫.value
3let a = $ref(1)
4// a可以直接使用不加.value
5a++
6</script>

此語法糖雖然遵守了js的語法,但是還是隻能在setup語法糖中才能使用,而且不支援在單檔案元件外使用,沒有讓這種語法生效在Vue的特定環境之外,所有編者還是有些失落

讓vue成為開發者編寫js的中間平臺,對開發者來說始終會產生一些心理負擔,【改變js的編寫方式】與【改變編寫的內容】之間的區別,還是讓開發者小心翼翼的考慮,爭取不會有一天被vue‘套住’。

只是可憐那波使用了第一波語法糖的開發人員,所幸團隊內還沒有在情況明朗之前貿然使用

4. ref語法糖改進文件

新的ref語法糖過多久就又被改進了,改進版主要是把全域性變數改為只有$這倆變數了

1<script setup>
2import { ref } from 'vue'
3
4const a = $(ref(1))
5// a可以直接使用不加.value
6a++
7// $$可以得到a的ref變數
8console.log($$(a))
9
10// 也就是說
11const aRef = ref(1)
12const a = $(aRef)
13// a可以直接使用不加.value
14a++
15console.log(aRef === $$(a))
16</script>
17

暈,目前為止,所有ref語法糖都只能看看,不敢在專案裡用


相關文章