初始化环境
在前面的文章中,我们通过vite
搭建了一个开发环境,但是实际上现在vite
并没有完善到支撑一个完整项目的地步,所以本文我们依然选择使用vue-cli
脚手架进行环境搭建。
小编使用的
vue-cli
版本是4.5.4
,如果您的版本比较旧可以通过npm update @vue/cli
来升级脚手架版本,如果没有安装可以通过npm install @vue/cli -g
进行安装
使用脚手架新建项目
-
在工作空间打开终端(
cmd
),然后通过vue create my-vue3-test
命令初始化项目 -
在第一步先选择
Manually select features
,进行手动选择功能 -
然后通过
Space
和上下键依次选择
Choose Vue version Babel TypeScript Router Vuex CSS Pre-processors Linter/Formatter
然后回车
-
然后提示选择
Vue
版本,选择3.x(Preview)
-
Use class-style component syntax?
选择n
,即输入n
然后回车 -
然后提示
Use Babel alongside TypeScript,输入
y` -
Use history mode for router
输入n
-
然后
css
预处理器选择Less
-
eslint
选择ESLint + Prettier
-
然后是
Lint on save
和In dedicater config files
-
最后一路回车即可完成项目搭建
启动项目
新建完项目之后,进入到项目中cd my-vue3-test
,然后执行 yarn serve
即可启动项目
启动之后即可通过访问http://localhost:8080/
访问项目
配置ant design vue
在当前Vue3.0
正式版还未发布之际,国内比较出名的前端UI
库中率先将Vue3.0
继承到自家的UI
库中的,PC
端主要是ant-design-vue
,移动端主要是vant
, 本文所有示例代码都会基于ant-design-vue
来进行,首先我们先安装ant-design-vue
- 安装依赖
yarn add ant-design-vue@2.0.0-beta.6 yarn add babel-plugin-import -D
- 配置
ant-design-vue
按需加载
进入项目根目录,然后打开babel.config.js
文件,将里面的内容修改为
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
// 按需加载
[
"import",
// style 为 true 加载 less文件
{ libraryName: "ant-design-vue", libraryDirectory: "es", style: "css" }
]
]
};
- 尝试使用
vue3 + antdv
来添加一个小页面, 我们直接将views/Home.vue
文件里面的代码替换为
<template>
<a-form layout="inline" :model="state.form">
<a-form-item>
<a-input v-model:value="state.form.user" placeholder="Username">
<template v-slot:prefix
><UserOutlined style="color:rgba(0,0,0,.25)"
/></template>
</a-input>
</a-form-item>
<a-form-item>
<a-input
v-model:value="state.form.password"
type="password"
placeholder="Password"
>
<template v-slot:prefix
><LockOutlined style="color:rgba(0,0,0,.25)"
/></template>
</a-input>
</a-form-item>
<a-form-item>
<a-button
type="primary"
:disabled="state.form.user === '' || state.form.password === ''"
@click="handleSubmit"
>
登录
</a-button>
</a-form-item>
</a-form>
</template>
<script>
import { UserOutlined, LockOutlined } from "@ant-design/icons-vue";
import { Form, Input, Button } from "ant-design-vue";
import { reactive } from "vue";
export default {
components: {
UserOutlined,
LockOutlined,
[Form.name]: Form,
[Form.Item.name]: Form.Item,
[Input.name]: Input,
[Button.name]: Button
},
setup() {
const state = reactive({
form: {
user: "",
password: ""
}
});
function handleSubmit() {
console.log(state.form);
}
return {
state,
handleSubmit
};
}
};
</script>
然后重启一下项目,就可以发现已经可以正常使用ant-design-vue
了。
Vue3.0新体验之setup
对于Vue3.0
的问世,最吸引大家注意力的便是Vue3.0
的Composition API
,对于Componsition API
,可以说是两极分化特别严重,一部分人特别喜欢这个新的设计与开发方式,而另一部分人则感觉使用Composition API
很容易写出来意大利面式的代码(可能这部分人不知道兰州拉面吧)。到底Composition API
是好是坏,小编不做评论,反正我只是一个搬砖的。而本小节介绍的setup
就是Composition API
的入口。
setup介绍
setup
是Vue3.0
提供的一个新的属性,可以在setup
中使用Composition API
,在上面的示例代码中我们已经使用到了setup
,在上文代码中我们在setup
中通过reactive
初始化了一个响应式数据,然后通过return
返回了一个对象,对象中包含了声明的响应式数据和一个方法,而这些数据就可以直接使用到了template
中了,就像上文代码中的那样。关于reactive
,我将会在下一小节为你带来说明。
setup 的参数说明
setup
函数有两个参数,分别是props
和context
。
props
props
是setup
函数的第一个参数,是组件外部传入进来的属性,与vue2.0
的props
基本是一致的,比如下面代码
export default {
props: {
value: {
type: String,
default: ""
}
},
setup(props) {
console.log(props.value)
}
}
但是需要注意的是,在setup
中,props
是不能使用解构的,即不能将上面的代码改写成
setup({value}) {
console.log(value)
}
虽然template
中使用的是setup
返回的对象,但是对于props
,我们不需要在setup
中返回,而是直接可以在template
使用,比如上面的value
,可以直接在template
写成
<custom-component :value="value"></custom-component>
context
context
是setup
函数的第二个参数,context
是一个对象,里面包含了三个属性,分别是
-
attrs
attrs
与Vue2.0
的this.$attrs
是一样的,即外部传入的未在props
中定义的属性。对于attrs
与props
一样,我们不能对attrs
使用es6
的解构,必须使用attrs.name
的写法 -
slots
slots
对应的是组件的插槽,与Vue2.0
的this.$slots
是对应的,与props
和attrs
一样,slots
也是不能解构的。 -
emit
emit
对应的是Vue2.0
的this.$emit
, 即对外暴露事件。
setup 返回值
setup
函数一般会返回一个对象,这个对象里面包含了组件模板里面要使用到的data
与一些函数或者事件,但是setup
也可以返回一个函数,这个函数对应的就是Vue2.0
的render
函数,可以在这个函数里面使用JSX
,对于Vue3.0
中使用JSX
,小编将在后面的系列文章中为您带来更多说明。
最后需要注意的是,不要在
setup
中使用this
,在setup
中的this
和你真正要用到的this
是不同的,通过props
和context
基本是可以满足我们的开发需求的。
了解Composition API
,先从reactive
和ref
开始
在使用Vue2.0
的时候,我们一般声明组件的属性都会像下面的代码一样
export default {
data() {
return {
name: '子君',
sex: '男'
}
}
}
然后就可以在需要用到的地方比如computed
,watch
,methods
,template
等地方使用,但是这样存在一个比较明显的问题,即我声明data
的地方与使用data
的地方在代码结构中可能相距很远,有一种君住长江头,我住长江尾,日日思君不见君,共饮一江水
的感觉。而Composition API
的诞生的一个很重要的原因就是解决这个问题。在尤大大在关于Composition API
的动机中是这样描述解决的问题的:
- 随着功能的增长,复杂组件的代码变得越来越难以阅读和理解。这种情况在开发人员阅读他人编写的代码时尤为常见。根本原因是 Vue 现有的 API 迫使我们通过选项组织代码,但是有的时候通过逻辑关系组织代码更有意义。
- 目前缺少一种简洁且低成本的机制来提取和重用多个组件之间的逻辑。
现在我们先了解一下Compositon API
中的reactive
和ref
介绍reactive
在Vue2.6
中, 出现了一个新的api
,Vue.observer
,通过这个api
可以创建一个响应式的对象,而reactive
就和Vue.ovserver
的功能基本是一致的。首先我们先来看一个例子
<template>
<!--在模板中通过state.name使用setup中返回的数据-->
<div>{{ state.name }}</div>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
// 通过reactive声明一个可响应式的对象
const state = reactive({
name: "子君"
});
// 5秒后将子君修改为 前端有的玩
setTimeout(() => {
state.name = "前端有的玩";
}, 1000 * 5);
// 将state添加到一个对象中然后返回
return {
state
};
}
};
</script>
上面的例子就是reactive
的一个基本的用法,我们通过上面的代码可以看到reactive
和Vue.observer
声明可响应式对象的方法是很像的,但是他们之间还是存在一些差别的。我们在使用vue2.0
的时候,最常见的一个问题就是经常会遇到一些数据明明修改了值,但是界面却并没有刷新,这时候就需要使用Vue.set
来解决,这个问题是因为Vue2.0
使用的Object.defineProperty
无法监听到某些场景比如新增属性,但是到了Vue3.0
中通过Proxy
将这个问题解决了,所以我们可以直接在reactive
声明的对象上面添加新的属性,一起看看下面的例子
<template>
<div>
<div>姓名:{{ state.name }}</div>
<div>公众号:{{ state.gzh }}</div>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
const state = reactive({
name: "子君"
});
// 5秒后新增属性gzh 前端有的玩
setTimeout(() => {
state.gzh = "前端有的玩";
}, 1000 * 5);
return {
state
};
}
};
</script>
上面的例子虽然在state
中并没有声明gzh
属性,但是在5s
后我们可以直接给state
添加gzh
属性,这时候并不需要使用Vue.set
来解决新增属性无法响应的问题。
在上面的代码中,reactive
通过传入一个对象然后返回了一个state
,需要注意的是state
与传入的对象是不用的,reactive
对原始的对象并没有进行修改,而是返回了一个全新的对象,返回的对象是Proxy
的实例。需要注意的是在项目中尽量去使用reactive
返回的响应式对象,而不是原始对象。
const obj = {}
const state = reactive(obj)
// 输出false
console.log(obj === state)
介绍ref
假如现在我们需要在一个函数里面声明用户的信息,那么我们可能会有两种不一样的写法
// 写法1
let name = '子君'
let gzh = '前端有的玩'
// 写法2
let userInfo = {
name: '子君',
gzh: '前端有的玩'
}
上面两种不同的声明方式,我们使用的时候也是不同的,对于写法1
我们直接使用变量就可以了,而对于写法2
,我们需要写成userInfo.name
的方式。我们可以发现userInfo
的写法与reactive
是比较相似的,而Vue3.0
也提供了另一种写法,就像写法1
一样,即ref
。先来看一个例子。
<template>
<div>
<div>姓名:{{ name }}</div>
</div>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const name = ref("子君");
console.log('姓名',name.value)
// 5秒后修改name为 前端有的玩
setTimeout(() => {
name.value = "前端有的玩";
}, 1000 * 5);
return {
name
};
}
};
</script>
通过上面的代码,可以对比出来reactive
与ref
的区别
reactive
传入的是一个对象,返回的是一个响应式对象,而ref
传入的是一个基本数据类型(其实引用类型也可以),返回的是传入值的响应式值reactive
获取或修改属性可以直接通过state.prop
来操作,而ref
返回值需要通过name.value
的方式来修改或者读取数据。但是需要注意的是,在template
中并不需要通过.value
来获取值,这是因为template
中已经做了解套。
在Vue3.0
优雅的使用v-model
v-model
并不是vue3.0
新推出的新特性,在Vue2.0
中我们已经大量的到了v-model
,但是V3
和V2
还是有很大的区别的。本节我们将主要为大家带来如何在Vue3.0
中使用v-model
,Vue3.0
中的v-model
提供了哪些惊喜以及如何在Vue3.0
中自定义v-model
。
在Vue2.0
和Vue3.0
中使用v-model
在Vue2.0
中如何实现双向数据绑定呢?常用的方式又两种,一种是v-model
,另一种是.sync
,为什么会有两种呢?这是因为一个组件只能用于一个v-model
,但是有的组件需要有多个可以双向响应的数据,所以就出现了.sync
。在Vue3.0
中为了实现统一,实现了让一个组件可以拥有多个v-model
,同时删除掉了.sync
。如下面的代码,分别是Vue2.0
与Vue3.0
使用v-model
的区别。
- 在
Vue2.0
中使用v-model
<template>
<a-input v-model="value" placeholder="Basic usage" />
</template>
<script>
export default {
data() {
return {
value: '',
};
},
};
</script>
- 在
Vue3.0
中使用v-model
<template>
<!--在vue3.0中,v-model后面需要跟一个modelValue,即要双向绑定的属性名-->
<a-input v-model:value="value" placeholder="Basic usage" />
</template>
<script>
export default {
// 在Vue3.0中也可以继续使用`Vue2.0`的写法
data() {
return {
value: '',
};
},
};
</script>
在vue3.0
中,v-model
后面需要跟一个modelValue
,即要双向绑定的属性名,Vue3.0
就是通过给不同的v-model
指定不同的modelValue
来实现多个v-model
。对于v-model
的原理,下文将通过自定义v-model
来说明。
自定义v-model
使用Vue2.0
自定义一个v-model
示例
- 组件代码
<template>
<div class="custom-input">
<input :value="value" @input="$_handleChange" />
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: ''
}
},
methods: {
$_handleChange(e) {
this.$emit('input', e.target.value)
}
}
}
</script>
- 在代码中使用组件
<template>
<custom-input v-model="value"></custom-input>
</template>
<script>
export default {
data() {
return {
value: ''
}
}
}
</script>
在Vue2.0
中我们通过为组件设置名为value
属性同时触发名为input
的事件来实现的v-model
,当然也可以通过model
来修改属性名和事件名,可以看我以前的文章中有详解。
使用Vue3.0
自定义一个v-model
示例
- 组件代码
<template>
<div class="custom-input">
<input :value="value" @input="_handleChangeValue" />
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: ""
}
},
name: "CustomInput",
setup(props, { emit }) {
function _handleChangeValue(e) {
// vue3.0 是通过emit事件名为 update:modelValue来更新v-model的
emit("update:value", e.target.value);
}
return {
_handleChangeValue
};
}
};
</script>
- 在代码中使用组件
<template>
<!--在使用v-model需要指定modelValue-->
<custom-input v-model:value="state.inputValue"></custom-input>
</template>
<script>
import { reactive } from "vue";
import CustomInput from "../components/custom-input";
export default {
name: "Home",
components: {
CustomInput
},
setup() {
const state = reactive({
inputValue: ""
});
return {
state
};
}
};
</script>
到了Vue3.0
中,因为一个组件支持多个v-model
,所以v-model
的实现方式有了新的改变。首先我们不需要使用固定的属性名和事件名了,在上例中因为是input
输入框,属性名我们依然使用的是value
,但是也可以是其他任何的比如name
,data
,val
等等,而在值发生变化后对外暴露的事件名变成了update:value
,即update:属性名
。而在调用组件的地方也就使用了v-model:属性名
来区分不同的v-model
。
总结
在本文中我们主要讲解了开发环境的搭建,setup
,reactive
,ref
,v-model
等的介绍,同时通过对比Vue3.0
与Vue2.0
的不同,让大家对Vue3.0
有了一定的了解,在下文中我们将为大家带来更多的介绍,比如技术属性,watch
,生命周期等等,敬请期待。本文首发于公众号【前端有的玩】,学习Vue
,面试刷题,尽在【前端有的玩】,乘兴裸辞心甚爽,面试工作屡遭难。 幸得每日一题伴,点击关注莫偷懒。
,下周一新文推送,不见不散。