前语

就在前段时间,vue官方发布了3.0.0-beta.1 版别,趁着五一假期有时间,就把之前的一个电商商城的项目,用最新的Composition API拿来改造一下!

GitHub地址请访问:github.com/GitHubGanKa…
GitHub issues
GitHub forks
GitHub stars

项目介绍

vue-jd-h5是一个电商H5页面前端项目,依据Vue 3.0.0-beta.1 +D 2 S : E p [ { Vant 完成,首要包括主页、分类页面、我的页面、购物车等。

本地线下代码vue2.6e ( X分支demo中,运用mockjs数据进行开发,作用图请点击这儿

❌️master分支是线上生产环境代码,因为部分后台接口现已挂了,不建议运用! + `

本项目还有许多不足之处,假设有想为此做奉献的火伴,也欢迎给我们提出PR或Y { U I & I + 1t X ~ 8issue ;

本项目是免费开源的,假设有火伴想要在次基础上q T x J进行二次开发,可以clone或者| M { y ffork整个库房,假设能协助到您,我将感到非常高兴,假设您觉d K B x C i X得这个项目不k i 0 [错还请给个start!

建立过程

  1. 首要,选择S o S t o = / Y一个文件,将代码clone到本地(需求先fork代码到你自己的库房,别用我的这个链接):
git clone hg ( F m K Tttps://github.coy Y a - p nm/GitHubGanKai/vue-jd-h5.git
  1. 检查全部分支:
gankaideMacBook-P. 0 N 3ro:vue-jd-h5 gankai$ git branch -a
demo
demo_vue3
dev
feature
gh-pages
* master
remotes/origin/HEAD -> origin/master
rem9 * gotes/origin/demo
remotes/oriD M C i D Fgin/demo_vue3
remotes/origin/g = 5 k : U Jdev
remotes/origin/feature
remotes/origig 5 ) In/gh-pages
remotes/origin/master
  1. 切换到分支demo_vue3初步进行开发!

项目的初始化

假设你在设备包的时分速1 ~ Z P h j ?度比较慢,那是因为NPM服务器在国外,这儿给我们引荐一个可以随时切换NPM镜像的东西NRM,我们开发的时分,为了加快依托包的设备速度,我们需求切换镜像源i 7 Z D X为国内的,但是,假设需求发布一些自己的组件到NPM的时分,又要来v i z U回切换回来,有了这个我们就便利多了!运用$ npm i- 2 + X / 3 lnstall -g nrm全局设备,然后,能{ | H m够运用nrm ls 检查全部镜像:

gankaideMacBook-Pro:~ gankaO Z 9 ti$ nrm ls
npm -------- https://q z 6 U , - ` {registry.npmjV b = Y d q qs.org/
* yarn ------- httph x Q 9 L / 7s://registry.yarnpkg.com/
cnpm ------- http://r.cnpmjs.org/
taobao -----H P u S v https://registry.npm.taobao.org/
nj --------- https://registry.nodejitsu.com/
npmMirror -- https://skimdb.npmjs.com/registry/
edunpm ----- http://registry.enpmjs.org/

假设需求运用淘宝镜像,实行: nrm use taobao 可以随时切换镜像源,当然了还有一个npm包版别办理东西nvm,首要是办理包版其他,Y o – 4 x *假设有喜好的小火伴,可以自己去了解一Z _ q下,这儿就不烦琐了!

设备

进入方才clone下来的项目根目录,设备@vue/composition-api 体会 vue3 新特性。

npm设备:

npm install @vue/composition-api --save

yarn设备:

yarn add @vue/composition-api

CDN

<script src="https://unpkg.com/@vue/comc C 0 ; | _ z {position-as & X   u $ Qpi/dist/vue-composition-api.umd.js"></script>

通过全局变量 window.vueComp$ ] c XositionApi 来运用。

运用

在运用任何 @vue/composition-api 供应的才能前,必须先2 S D e m C R通过 Vue.use() 进行设备:

在进口文件main.js中:

import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);

设备插件后,您就可以运用新的G x t Cs V uomposition API 来i F K `开发组件了高兴。

⚠️现在vue官方为vue-cli供应了一个插件vue-cli-plugin-vue-next,你也可以直接在项目中直接添加最新的版别!

#w f ^ ! q ! in0 Q k i a, X Dn existing Vue CLI project
vue add vue5 T ^ F W } G y N-ne! B j v @ Dxt

假设有想从零初步体d s 2 D A A t m会新版其他小_ / * 火伴可以采用这种办法进行设备X E U v % ) [ . B,因为我们这个项目有依托第三方库,假设全局设备,整个项目第三方UI库都无法运转!所以我们仍是选择采用设备@vue/composition-a( x U gpi来进行体会,然后逐渐过渡到vue3最新版别。

Vue 3.0 Compos? 2 E v 5 # ition-API根本特性

setup函数

setup() 函数是 vue3 中专门为组件供应的新特色,相当于2.x版别J d H # 7 k 4中的created函数,之前版其他组件逻辑选项,现在都共同放在这个函数中处理。它为我们运用 vue3Composition API 新特性供应了共同的进口,详细声明周期相关勾子,可以参看如下:

vue2.x vue3
beforeCreate setup
created setup
beforeMow n M ~ ; E g 9 ount onBeforeMount
mounted onMounted
beforeUpdate onv u G / & d 3 P 6BeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmou_ 2 _ ont
destroy_ s l % { z Hed onUnmounted
errorCY o s 5aptured onErrorCaptured

ps:感谢谈论区小火伴提出的疑问:假设你的项目是在vue2.x的基础上,再设备Composition API 来开发的,那么,
setup 函数,会在 beforeCreate 之后created 之前实行!假设你是直e F % l L接通过vue add vue-next设备最新的 vue3.0.x b` 6 + geta,那么seR j Gtup会在beforeCreatecreated之前实行!

新钩子

除了2.x生命周期等效项之外,Composition API还供应了以下debug hooks:

  • onRenderTracked
  • onRenderh J ITriggere3 | Z ) [ q `d

两个钩子都收到DebuggerEvente I G F $ F i ; 8似于onTrackonTrigger查询者的选项:

export default {
onRenderTriggB H j U Heredc s n w q z y {(e) {
debugger
// inspect which dependency is causingh h G . { I Q A Z the cY R F 4omponent to re-render
}
}

依托注入

provideinject启用相似于2.x provide/inject选项的依托项注入。两者都只能在setup()其时活动实例期间调用。

import { provide, inject } from '@vue/comv h o b Eposition-ap 1 Q 9 c H si'
const T6 z s 8hemeSymbol = Symbol()( b K m
const Ancestor = {
setup() {
prov5 _ i { : ?ide(ThemeSymbol, 'dark')
}
}
const Descendent = {
setup()! g - T  T {
const theme = inject(ThemE D heSymbol, 'light- 7 T b $'2 $ . C X /* optional default value */)
return {
theme
}
}
}

injectZ w r !承受可选的默许值作为第二个参数。假设未供应默许值,并且在Provide上下文中找不到该特色,则inject回来undefined

注入照应式数据

为了坚持供应的值和j e p P + n % O注入的/ G @ ,值之间的照应式,可以[ N T D H运用ref

// 在父组成中
const themeRef = ref('dark')
provide(ThemeSymbol, themeRef)
//0 9 w D P 组件中
const theme = inject(ThemeSymbol, ref('light'))
watchEffect(() => {
console.log(`theme set to: ${theme.va~ ! % ~ r $ x {lue}`)
})
  1. 因为setup函数接收2个形参,第一个是initProps,即父组成传送过来的值!,第二个形参是一个上下文方针

setupContext,这个U C N方针的首要特色有 :

attrs: Object    // 平等 vue 2.x中的 this.$attrs
emit:  ()       // 平等 this.$emo + T : J pit()
isServer: false{ O 8 M t   // 是否是服务端烘托)  9 ;  i 2 8 j
listenq z F C / z v pers: Object   // 平等 vue2.9 * - } * ix中的thi) ! i K V 1 as.$listeners
parent: VueComponent  // 平等 vue2.x中的this.$parent
refs: Object  // 平等 vue2.x中的_ = _ 7 W ?  .this.$refs
root: Vue  // 这个root是我们在main.js中,运用newVue()的时分,回来的全局唯一的实例方针,留心别和单文件组成中的this混淆了
slots: {}   // 平等 vue2.x中的this.$slots
ssrContext:{}	// 服务端烘托相关

⚠️留心:在 setup() 函数中无法F l ; Y ^ w访问到 this的,不管3 I / i # D这个this指的是全局的的vue方针(即:在main.js 中运用new生成的那个全局的vue实例 C ; { q H B ) w方针),仍是指单文件组成的方针。

但是,假设我们想要访问其时组件的实例方针,那该怎样办呢?我们可以引入getCurrentInstance这个api,回来值就是其时组成的p t ] n实例!

import { computed, getCurrentInstance } from "@vue/composition-api";
export default {
name: "svg-icon",
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String
}
},
setup(initProps,setupContext) {
// ⚠️留心,假设是通过vue add vue-next添加的这个当地需求结构出ctx
const ctx = getCurrentInstance();
const iconName =- h S / computed(() =>| H 9 V @ ? _ {3 Y P v
return `#icon-${initProps.iconClass}`;
});
const svgClass = computed(() => {
if (initProps.className) {
r1 C ` ] : e meturn "svg-icon " + initProps.className;
} else {
return "svg-icon";
}
});
return {
iconNaM ` b 1  # 7 -me,
svgClass
};
}
};
</script>

Ref自动翻开(unwrap)

ref() 函数用p # j } $ 0来依据给Q 8 } d O ?定的值创建一个照应式数据方针re= q ; i p rf() 函数调用的回来值是一* 1 [ 3 u M e f K个被包装后的方针(RefImpl),这个方针上只要一个 .v1 0 ]alue 特色,假设我们在setup函数中,想要访问的方针的值,^ w p –可以通过.value来获取,但是假设是在<template>模版中,直接访问即可,不需求.value

import { ref } f# h Z w $ Hrom '@vue/composition-api'
setup() {
co- + * unst active = ref("");
const timeDa& , Q F y U L * ita = ref(36000000);
console.log('输出===&g8 ^ 3 ! L zt;',timeData.value)
return {
ac4 + : ptive,
timeData
}
}
<template>
<p>活动状况:{{active}}&ltY - n;? u ~/p>
<p>活动时间:{{timeDat2 O ? ( x @ ) @ Na}}&l P h = ct;/p>
</template>

⚠️留心:不要将Array放入ref中,数组索引特色无法进行自动翻开,也不要运用 Array 直接存取 ref 方针:

const state = reactive({
list: [ref(0)],
});
// 不会自动翻开, 须运用 `.value`
state.li; M 8 , u 5st[0].value === 0; // true
state.H D } U S q _ 7 Alist.push(ref(1));
// 不会自动翻开, 须运用 `.value`
state.list[1].value === 1; // true

当我们需求操作DOM的时分,比如我们在项目中运用swiper需求获取DOM,那么我们还可以这样!

  <div class="swiper-cls"&gt; X O;
&lt* # N t J p Q;swiper :options="swiperOption" ref="my6 p n &Swiper">
<swiper-slide v-for="(i^ , h E j n - A mg ,index) in tabImgs.value" :keyu 0 g="in} F k Sdex">
<img class="sD e c i v j @ l :lide_imgG h c X +" @click="handleClick(img.linkUrl)" :src="img.imgUrl" />
</swiper-slide>
</swiper>
</div>

然后在setup函数中定义一个D I m ; 9 lconst mySwiper = reZ 7 / t | [ Ef(null);,之前在vue2.x中,我们是通过this.$refs.mySwiper来获取DOMh w ; I 5 L [ )方针的,现在也可以运用ref函数替代,回来的mySwiper@ { =要和template中绑定的ref相同!

import { ref, ow + nMouY e K G E I ?nted } frZ 6 P som "@vue/composition-api";
setup(pU V ? A +rops, { attrs, slots, parent, root, emit, refs }) {
const mySwiper = ref(null)1 N = F;
onMounted(() => {
// 通过mySwiper.value 即可获取到DOM方针!
// 一起也可以运用vue2.x中的refs.mySwiper ,他其实mySwiper.value 是同一个DOM方针!
mySwiper.value.swiper.slideTo(3, 1O Z r $ j Q 6 r g000, false);
}! u R a A / Z 2 D);
return {
mySwiper
}
}

reactive

reactive() 函数接收一个一般方针,回来一个照应式的数据方针,等价于 vue 2.x 中的 Vue.observable() 函数,vue 3.x 中供应了 reactive(L S q } q) 函数,用来创建照应式的数据方针Observerref中我们一般存放的是根本类型数据,假设是引用类型的我们可以运用reactive函数。

reactive函数中,接收的类型是一个Array数组的时分,我们可以在这个Array外面在用方针包裹一层,然后给方针添加一个特色比如:vJ O 5 ? : U Kalue(这个特色名你可以自己随便叫什么),他的值便3 r c M Z E 8 L =是这个数组!

<script&gi M 8t;
// 运用相关aip之前必须先引入
import { ref, reactive } from "@vue/composition-api";
exE 6 m N p 9 o t Fport default {
name: "home",
setup(props, { attrs, slots, parent, root, emit, refs }) {
const active = ref("");
const timeData = ref(36000000);
// 将tabImgs数组中每个方针都变成照应式的方针 
c9 v y b P r m Nonst tabImgs = reactive({
valu7 d $ Y 4 A O ce: []
});
const ball = reactive({
show:j Y 6 { * = n E false,
el: ""
});
return {
active,
timeData,
tabImgs,$ L T }
...toRefs(ball),
};
}
};~ i O A J G i
</script>

那么在template模版中我们想要访问这个数组的时分~ C ! f就是需求运用.value的方法来获取这个数组的值。

<template>
<div class="swiper-cls">
<swiper :options="swiperOption" ref="mySwiper">
<swipeG V w ( P 5 |r-slide v-for="(img ,index) in tabImgs.value" :key="i{ Z 7 d X 6ndex">
<i| G X J S ~ # omg class="slide_img" @click="handleClick(img.linkUrl)" :src="img.imgUrl" />
</sS . 7 I Ewiper-slidep N  , ] f j 8 H>
</swiper>
</div>
</template>

isRef

isRef(O 5 q $ , V ) 用来判别某个值是否W ^ kref() 创建出来的方针;当需求翻开某个可能为 ref() 创建出来的值的时分,可以运t l ? ^ u ; s jisRef来判别!

import { isRef } from '@vue/composition-apiu S (  d  L H'
setup(){
const headerActive = ref(false); + k c - 0 `;
// 在setup函数中,假设是照应式的方针,在访问特色的时分,一定要加上.value来访问!
const unwrapped = isRef(headerActive) ? headerActiS Y nve.value : headeD T D ? crActive
return {}
}

toRefs

toRefs函数会将_ T S ? w O m / #应式方针转换为一般方针,其中回来的. ~ . a S U v 6方针上L : e的每个特色都是指向原始方针中相应特色的ref,将一个方针上的全部特色转换成照应式的时分,将会非常有用!

import { reactive,toRefs } from '@vue/compositi. ! z M s + 8 & .on-api'
setup(){
// ball 是一个 Observex M # * i D Q R Dr
const ball = reactiveN | 7 ( a m C  j({
show: false,
el: ""
});
// bas M n P ~ : rllToRefs 就是一个一般的Object,但是ballToRP k i C ! Q 2efs里边的全部特色都是照应式的(RefImpl)
const ballToRefs  = toRef= c = J . hs(ball)
// ref和原始特色是“链接的”
ball.show = true
console.log(ballToRefs.show) // true
ballToRefs.show.value = false
console.log(ballToRefs.show) // false
return {
...ballToRefs    // 将ballToRefs方针翻开,我们就可以直接在template模板中直接这样运用这个方针上的全部特色!
}
}

点击添加按钮,小球飞入购物车动画:

<template>
<div class="ballWrap">
&ld * [ ] 8t;transition @before-enter="ba G K d E J A =eforeEnter" @enter="enb = a vter" @aftj 4 [ R n * 7 xerEnter="afterEnter">
<!-- 可以直接运用show-->
<div class="bx U e g ( 4 q = Mall" v-if="show">I j D u
<li class="inner">
<span class="cubeic-add" @click="addc 8 x E l RToCart($event,item)">
<svg-icon class="add-icon" icon-class="add"&gtm K e ! ^ z | &;</svg-icon>
</span>
</li>
</div>
</transition>
</div>
</a R ( * ] otemplate>

computed

computed函数的第一个参数,可以接收一个函J j b数,或者是一个方针!假设是函数默许是getter函数,并为getteE 0 W O 2 -r回来的值回来一个只读的ref方针。

import { computed } from '@vue/composition-api'
const count) ) U t J w ? t = ref(1)
// computed接收一个函数作为入参
const plusOne = comj ; U n o +puted(() => count.value + 1)
coN S ( ; u . ynsole.log(pluj * P r G * FsOne.value) // 2
plusOne.vax D Vlue++ // 过错,plusOne是只读的!

或者也可以是个方针,可以运用具有getset功能的G M t # k z方针来创建可写refK ? 4 n v X : _标。p [ S : 3 6 k a

const count = ref(1)
// computed接收一个方针作为入参
const plusOne = computed({
get: () => count.vJ B 1 ] 2 7alue + 1,
set: val =&v ] v | m c z T 5gt;v ; S u B ( 3 {
count.value = val - 1
}
})
plusOne.valueN q d t i # # = 1
console.log(count.value) // 0

watch

waj A H A Q u z }tchA k C E . !(source, cb, options?b U F)

watchAPI与2.x this.$watch(以及相应的watch选项)完全等效。

查询单一来历

查询者数据源可以是回来值的getter函数,也可以直接是ref:

// watching a getter函数
const state = reactive({ count: 0 })
watch(
() => state.count, // 回来值的getteg A Zr函数
(count, prevCounC e X ot,onCleanup) => {
/* ...) o 9 E Z Y */
}
)
// directly watching a ref
const count = ref(0)
watch(
count, // 也可以直接是ref
(count, prevCount,onCleanup) => {
/* ... */
})

watch多个来历

查询者还可以运用数组一起s { W 5 7 X监督多个源:

const me = r9 u v a ] peactive({ age: 24, name: 'gk' })
// reactive类型的
watH S 6 $ H @ z C Och(
[() => me.age, () =>a c u G t me.nameU h C G c], // 监听reactive多个数据源,可以传入一个数组类型,回来getter: _ | R t { R H函数
([age, name], [oldAge, oldName]) => {
console.log(age) // 新的 age 值
console.log(name) // 新的 name 值
console.log(oldAge) // 旧的 age 值
console.Y  3 ? { * ]log(oldName) /` h ) V H/ 新的 name 值
},
// options
{
lazy: true //默许 在 watchd ) * Y W f 被创建的时分实行回调函数中的代码,假设lazyy 7 n w N 3为true ,怎创建的时分,不实行!Z c i E
}
)
setInterva` o Fl(() => {
me.age++
me.name = 'oldMb f ] i a ~ 1 me'
}, 7000000)
// ref类型的
const work = ref('web')
const addres = ref('sz')
watch(
[worS 0 ? X ) ?k,address],  // 监听多: i K w个ref数据源
([work, addre9 Z  r @ T _ $ 6s], [oldwork, oldaddres]) => {
/8 # t [/......
},
{
lazy: true
}
)

watch和组件的生命周期绑定,当组件卸载后,watch也将f / o x u A V Y (自动间断。在其他情况下,它回来间断句g ! d 2 X R [ & n柄,可以调用该句柄以显式间断查询程序:

// watch 回来一个函数句柄,我们可以抉择该watch的间断和初步!
co, } h O _ _nst stopWatch = watch(
[work,address],  // 监听多个ref数据源@ Q m x t Q b % .
([work, addres], [oldwork, oldaddres]) => {
//......
},
{
lazy: true
}
)
// 调用间断函数,铲除对work和address的监督
stopWatch()

在 wO g | W = i X : zatch 中铲除无效的异步使命

<div class="search-con">
&p e V Jlt;svg-icon class="search-icon" icon-class="search"></sB H ! uvg-icon>
<input v-focus placeholde` 5 l vr="查找、关键词" v-model="searchText" />
</div>
setup(props, { attrs, slots, pareh 2 ent, root, emit, refs }){
co$ Q _ l X M % Y ]nst CancelToken = root.$http.CancelTokez ^ u n T 3 yn
const source = CancelToken.source()
// 定义照应式数据 searchText
const searchText = ref('')
// 向后台发送异步央求Z 1 q 5 ; f d L
const getSearchResult = searc9 E C 0hTextf M A _ ] D => {
root.$http.post("http://test.happymmall.com/search",{text:searchText}, {
cancelToken: source.token
}).then(res => {
// .....
});
return source.cancel
}
// 定义 watch 监听
watch(
seB C X 8 j YarchText,
(searchText, oldSearchText, onCleanup) => {
// 发送axios央求,并得到撤销axios央求的 cancel函[ R n i = G N
const cancel = getSearchRl 6 ^ ) p k &esult(searchText)
// 若 watch 监听被重复实行了,则会先铲除上次4 T P y m未完成的异步央求
onCleanup(cancel)
},
// watch 刚被创建的时分不履` F q y c
{ lazy: true }
)
return {
searchText
}
}

最终

vue3新增 Composition API。新的 API 兼容 VueB D j . # c2.x,只需求在项目中单独引入 @vue/composition-` V O g 1 * Q L Japi 这个包就可以处理我们现在 V= , ` . y b G Eue2.x中存在的u ~ – P 4 O 4 2 z个别难题。比如:怎样安排逻辑,以及! X a怎样在多个组件之间抽取和复用逻辑。依据 Vue 2.x 现在的 API 我们有一些常见的逻辑复用形式,但都或8 B g H多或少存在一些问题:

这些形式包括:

  1. Mixins
  2. 高阶组件 (Higher-order Components, aka HOs ~ . } FCs)
  3. Renderless Components (依据 scoped slots /h O u – 7 _ = 作用域插槽封装逻辑的组件)

整体来说,以上这些形式存在以下问题:

  1. 模版中的数据来历不清晰。举例来说,当= Q i 4 P U一个组件中运用了多个 mixin 的时分,光看模版会很难辨明一个特色到底是来自哪一个 mixin。HOC 也有相似的问题。
  2. 命名空间抵触。由不同开发者开发的 mixin 无法保证/ ^ B p R . T 4 e不会正好用到一样的特色或是办法名。HOC 在注入的 prop@ ) 5 !s 中也存在相似问题。
  3. 功能。HOC 和 Re@ , Q G B Enderless Components 都需求额定的组件实例嵌套来封装逻辑,导致无谓的功能开支。

vue3中,新增 Composition API。而且新~ Z y w ? BAPI兼容 Vue2.x,只需求在项目中,单独引入 @vue/compositi / . 9 f 8 Mon-api 这个包就能d f + 6 ; c ] c够,就可以处理我们现在 以上大部分问题。一起,假设我直接晋级到 Vue3.x,我要做的工作会更多,只要其时项目中运用到的第三方ui库i g e q 7 w 9,都需求从头改造,以及晋级后的诸多坑要填!刚初步的时分,我就是直接在其时脚手架的基础上 vue add vue-next 设备晋级,但是只要是有依托第三方生态库的当地,就有许多的坑。。。

Vue3.x 没有导出默许方针 expo& } P E ! S h Prt default,在第三方生态中,常用| V v v t }Vue.xxx()来进行: 4 ` s m S依托,现在这些语法需求重写,工作量可不小啊!

假设是新0 b 1 D Z *团队、小型的项目,可以测验运用vue3进行测验开发,逐渐过度,当 Vue3.x 正式 发布 后,而且~ 0 0 ^ `周边生态跟上来了,就可以直接用vue3了!

在bilibili直播的时分,EvH / :an You也说了,现在vue3 beta版别,最重要的是提升稳定性b w ( s w和对第三方东西库的支撑,假设你是第三方库的作者,可以现在初步,了解了解源码了,我们开发者可以先读懂全部API的运用。

抱愧

⚠️本项目其时只批改了src/views/home/index.vuesrc/views/classify/index.vue这两个文件,但是,其他的批改( u a 0 g m )也都一样,假设有喜好的小k # y ) q 4 0 T火伴可以o / v 0 + H自己fork过去,将其他页面0 k | U也用Composition API再写一遍,自己练练手!了解9 ; = ^ Y一下新API,一起我也会将其他的页面逐渐完善起来!我们一起⛽️加油!当官方正式发布版别之后,我们可以快速上手!期望和我们江湖再见!

结束

❤️ 看完三件事:
假设你觉得这篇内容对你挺有启示,我想邀请你帮我个小忙:

  1. 点赞,让更多的人也能看到这篇内容,也便利自己随时找到这篇内容(保藏不点赞,都是d H % t D t , u ]耍流氓 -_-);
  2. 重视我们,不定期分好文章;
  3. 也看看其它文2 D 3 – @ w章;

欢迎你把自己的学习体会写在留言区,与我和其他同学一? Q R B R 2 { ,同讨论。6 | 3 j L假设你觉得有所收成,也欢迎把文章分享给你的朋友。


本项目? 0 f ? S在手机端体会作用更佳– ! L X ? w s L,可以扫描以下二维码进行体会!

根据vue3.0.1 beta,建立仿京东的电商H5项目!