前言:本文内容来源于我的听课记录。开始写本文时,我接触Vue并不久,本文是对网课内容进行了一个整理,加上了一些自己的理解。因此也可以算是一个纯小白教程,有不足的地方还请各位大佬赐教!
由于我自己是先从相对简单的微信小程序开始学习的,对小程序的代码风格较为熟悉,因此在本文中会出现部分Vue与小程序对比的内容,不喜勿喷哦~
Vue 3.0 现在的问题不是在于 Vue 3.0 核心库本身,而是在于整个Vue的生态。
如:Vue Router、VueX(全局状态转管理),等第一方生态的一些库。
此外还有一些Vue第三方的组件库。
原来的 options API 变成了现在的 composition API (由 原来的选项式的API风格,变成了 现在的组合式的API风格)。
注:小程序的API风格和Vue 2.x的API风格就是options API的风格
在2.x的时候还有一些面向对象的概念(如:var vm = new Vue(el template) )。在3.0版本里面,它变得更加函数式了,更多的时候没有new Vue() 了,3.0都是从Vue的核心库里面引入一个一个的函数。
例:2.x需要通过Vue.component()去注册一个Vue的组件,3.0是从Vue的函数库里直接引入一个component函数去注册一个Vue的组件。
3.0和2.x整体上的变动其实是不大的,很多核心概念和提供给我们的API,都是没有太大变化的。
学习3.0的版本,必须在思维上有一个比较大的变化。2.x组织代码的方式都是用options API的方式在组织的,options API还是有面向对象的影子在里面。在3.0里面,Vue的思想要完全切换到函数式编程。现在的Vue变得更加扁平化了,也变得更加灵活些了。让Vue变得更好维护,适合去开发更大的项目(软件工程最重要的就是维护)。
https://v3.cn.vuejs.org/guide/composition-api-introduction.html
有2.x基础的开发者建议先看文档。
注:对小程序非常了解的话,学习Vue是非常简单的,很多思想是一致的(如:数据绑定、列表循环、条件渲染,等常用机制)。不过Vue还是比小程序要复杂很多,如:Vue支持非常丰富的双向数据绑定 & 灵活多样的监听机制。
四、服务端渲染/前端渲染 1. 概述不能说Vue/React/AngularJS是用来开发单页面/多页面的。
重要标志:看HTML是在哪里渲染的。(如:服务端渲染、前端渲染)
即:HTML+CSS+数据,这3者是在哪里产生的。
误区: 不能说单页面就是前端渲染,多页面就是服务端渲染。(虽然绝大多数前端渲染确实是单页面的,但也可以用来做多页面)
所谓的渲染,就是把数据填充到HTML里面,并没有特别神秘的技术在里面。
对于传统的Web项目来说,HTML+数据 的结合,在 服务端 由服务端结合在一起,就是服务端渲染。
API只返回数据给前端,但在非常传统的开发模式里,数据是不会直接返回的。服务端返回给开发者的并不是单纯的数据,而是 HTML+数据,最终返回的还是HTML(包含数据的HTML)。
怎么在服务端去做 HTML+数据 的服务端渲染呢?
各大服务端Web框架(如:SpringBoot、Flask),只要是一个Web框架,都要提供模板引擎,通过模板引擎去进行HTML+数据的结合。最终返回HTML,这就是服务端渲染。
现在对于Vue/React/AngularJS,包括小程序,前端代码肯定不是从API里面来的。
事实上,当我们用 Vue/React/AngularJS/小程序 开发时,服务器返回的仅仅只是一个模板,也就是HTML,这个HTML里面可能还包含了CSS或动态的JavaScript代码,通常来讲它是没有数据的。
那么数据是怎么来的呢?这些数据事实上是通过JavaScript去加载服务器的API,从而返回数据。然后由前端自身,把数据都渲染到HTML里面去。所以这是一个前端渲染的过程。
比如说小程序,小程序不是放在我们自己的服务器上的,而是放在腾讯的服务器或是其他第三方的云端上的。我们是首先下载了小程序这个应用程序,然后小程序的应用程序和服务端的应用程序去进行通信。
所以说现在的前端,严格意义上来说已经不再是属于前端了,和服务端其实是对等的,所以说是2个应用程序之间的通信。
以前用服务端渲染时,只需要部署服务端就可以了,前端是不需要独立去部署的。对于现在的前端渲染模式来讲,服务端要部署,前端也可以独立去部署,如 可以放到CDN 或 其他地方。
前端渲染和服务端渲染并不是完全孤立的,两者可以同时存在。
如:大部分数据进行服务端渲染,少部分数据进行前端渲染。大部分数据被服务端填充到HTML里面,少部分数据由于它们是动态的,更多的在HTML里面利用js去发ajax请求。
如果我们选择用服务端渲染,往往我们用的更多的可能是这样的:Web框架 + 模板引擎 去进行服务端渲染,最终由服务器提供给我们一个已经填充了数据的HTML。这是用服务端渲染的一个技术栈。
如果我们选择用前端渲染,往往我们经常使用的就是 Vue/React/AngularJS ,这些是专门用来开发应用程序的。然后由它们负责和服务端的应用程序进行通信,再由Vue/React/AngularJS进行渲染到模板上。
虽然Vue/React/AngularJS非常火非常流行,可以说是前端必学的技术栈,但在真正大型网站里,还是以服务端渲染(Web框架 + 模板引擎 的方式)为主。因为 前端渲染有一个致命的缺点,就是对于SEO(搜索引擎优化)的支持不是很好。 也就是说前端渲染很难被搜索引擎搜录类。如果一个网站不能被你的用户从搜索引擎里面搜索到的话,事实上这个网站是没有太大的意义的。所以要做一个Web网站,最基本的要保证的就是要被很容易地搜索到。
Vue/React/AngularJS 真正的用处并不是在开发这些传统的门户网站上面。它们 更加适合的场景 :
开发CMS(后台管理系统)CMS是不需要去支持SEO的。开发App里内置的H5
现在的App很多都不是原生开发的了,也就是说不是全都用Java(Android里的)或Swift(iOS里的)去开发的了,更多的时候,App里的开发都是混合式开发。App本身就不具备被搜索引擎搜录的特性。 六、如何用Vue.js进行开发
有两种模式:
CLI(脚手架)去创建一个应用程序(用得更多)和小程序类似,创建小程序时自带很多文件,小程序开发工具其实就是内置了一个脚手架。用引入vue.js。 2. 创建vue实例
简要说明:
本文中的HTML代码及JavaScript代码书写位置如下:
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title>
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scale=no">
<script src="vue.global.js">script>
head>
<body>
body>
<script>
// JavaScript代码
script>
<style>
/* CSS样式 */
style>
html>
vue2.x 使用 const vm = new Vue();
定义一个Vue的实例,这个Vue实例是被new出来的,然后在Vue实例化时,传入各种参数。
例:
const vm = new Vue({
el: "#app", // 指明Vue的根元素,通常为 id为app的div
data: {
key: value,
},
template
})
以上这种形式就是很典型的Options API。
vue3.0写法:
const {createApp} = Vue // ES6写法,结构赋值,引入createApp方法
const value = "hello"
const app = {
setup(){ // ES6写法,等同于 setup: function(){}
return {
value // ES6写法,等同于 value: value
}
}
}
createApp(app).mount('#app') // mount:挂载;调用createApp方法,把我们创建的Object对象app传进来,然后挂载到html中的dom节点#app。
在html中用双花括号包裹起来,就能拿到上面return的值了。
<div id="app">
{{value}}
div>
七、Vue的指令
Vue的指令均以 v-
开头,如:v-text
、v-html
、v-bind
、v-on
等,指令内部是不需要加双花括号的。
例:
<div id="app">
{{value}}
<div v-text="value">div>
<div v-html="value">div>
<a v-bind:href="url">点击a>
<img v-bind:src="url">img>
<div v-on:click="onClick(xxx)">点击此处触发onClick事件div>
<a v-bind:[attr]="url">点击a>
<a v-bind:[attr+'f']="url">点击a>
<div v-text="flag ? value1 : value2">div>
div>
1. Vue常用指令 及 与小程序对比
1.1 v-bind
指令(:
)
html代码:
<img v-bind:src="url">img>
<img :src="url">img>
同小程序中的:
<image src="{{url}}">image>
1.2 v-on
指令(@
)
来看一个简单的例子
html代码:
<div id="app">
<div v-on:click="onClick">点击此处触发onClick事件div>
<div @click="onClick">点击此处触发onClick事件div>
div>
JavaScript代码:
const {createApp} = Vue
const app = {
setup() {
function onClick() {
alert('hello')
}
return {
onClick,
}
}
}
createApp(app).mount('#app')
同小程序中的:
<view bind:click="onClick">点击此处触发onClick事件view>
此例中绑定的是一个click事件。同理,也可以绑定一个自定义事件。
1.3v-if
指令 与 v-show
指令
v-if
html代码:
<div v-if="flag" v-text="value">div>
同小程序中的:
<view wx:if="{{flag}}">{{value}}view>
v-show
html代码:
<div v-show="flag" v-text="value">div>
同小程序中的:
<view hidden="{{!flag}}">{{value}}view>
若flag
值为false
,两者都不会显示内容。
但使用v-if
时,这个不会出现在dom结构中。
使用v-show
时,这个会出现在dom结构中,属性中会自带
。
总结:v-if
事实上是一种条件渲染,为true就显示,为false就不显示。而v-show
一定会显示,至于能不能看到,是用style样式去控制的。
那么在使用的时候到底该选择使用哪一个呢?
由于dom节点初始化的渲染是要消耗一定性能的,如果需要频繁的切换状态,则用v-show
更合适,此时如果用v-if
就会反复渲染dom节点,会频繁地消耗性能。
若初始化的成本较小,使用两者均可。
对于一个dom节点,若无需频繁切换状态,且在渲染时成本和开销非常大,如某个div
下有非常复杂的子dom结构,此时应优先选择v-if
,因为v-if
有可能让页面根本不去渲染这个dom节点。
v-if
、v-else
、v-else-if
例1 html代码:
<div v-if="flag" v-text="value1">div>
<div v-else v-text="value2">div>
同小程序中的:
<view wx:if="{{flag}}">{{value1}}view>
<view wx:else>{{value2}}view>
例2 html代码:
<div v-if="nubmer===1">{{value1}}div>
<div v-else-if="nubmer===2">{{value2}}div>
<div v-else>{{value3}}div>
同小程序中的:
<view wx:if="{{number===1}}">{{value1}}view>
<view wx:elif="{{number===2}}">{{value2}}view>
<view wx:else>{{value3}}view>
1.5 列表渲染 v-for
遍历数组 html代码:
<ul>
<li v-for="(item, index) in list">{{item}}{{index}}li>
ul>
同小程序中的:
<view wx:for="{{list}}">
<view>{{item}}{{index}}view>
view>
在Vue中,要循环哪一个标签,就把v-for加在哪个标签上。
小程序是加在外层标签上。
遍历对象 html代码:
<ul>
<li v-for="(value, key, index) in object">{{index}}-{{key}}:{{value}}li>
ul>
1.6 双向数据绑定 v-model
& Vue3.0的 ref
/ reactive
包装响应式对象
首先明确一点:“双向”并不是Vue的特点,“绑定”才是。
双向数据绑定是指:让数据可以从JS里流向HTML,反过来,HTML里的数据发生变化了之后,JS里对应的相同变量的值也会发生改变。
例:
html代码:
<div id="app">
<input v-model="age" type="text"/>
<button @click="onClick">提交button>
div>
JavaScript代码:
const {createApp, ref} = Vue
const age = ref(18) // 此处是把数字包装成了一个响应式对象
const app = {
setup() {
function onClick() {
alert(age.value)
}
return {
age,
onClick,
}
}
}
createApp(app).mount('#app')
ref和reactive都可以把一个对象包装成一个响应式对象。
例:
html代码:
<div id="app">
<input v-model="profile.age" type="text"/>
<button @click="onClick">提交button>
div>
JavaScript代码:
const {createApp, reactive} = Vue
const profile = reactive({
age: 18
}) // 此处是把对象包装成了一个响应式对象
const app = {
setup() {
function onClick() {
alert(profile.age)
}
return {
profile,
onClick,
}
}
}
createApp(app).mount('#app')
ref和reactive接收的参数是不同的。通常我们往ref传参传的是JavaScript基本数据类型,如:数字。而往reactive传参传的是一个Object对象。
ref的最佳实践是传入一个基本类型,事实上它也可以传入Object对象。根据文档描述,可以知道:如果传入 ref 的是一个对象,将调用 reactive 函数进行深层响应转换。
文档如图:
实现双向数据绑定,单用 v-model
指令是不行的,实现的关键是:必须得有响应式对象。
另外,v-model
指令并不能用在所有的标签上,事实上,只有 input
、textarea
、select
标签上可以使用 v-model
。v-model
更多时候是用来辅助可输入的html。
v-model
的实质其实是:用 v-bind
去绑定 value
属性(如:v-bind:value="age"
),这也是为什么在 input
标签上,用了 v-model
就不需要再去使用 value
了。另外,它提供了一个监听事件,即:用 v-on
去监听响应式对象的变化。
因此,v-model
并不是实现双向数据绑定的核心,响应式对象才是。
同理,单向数据绑定也需要是响应式对象,单向数据绑定意味着JS里的变量发生改变,HTML里也要跟着相应地改变。如果不用响应式对象,JS变化时,HTML只是静态地展示,不会动态地发生变化。
八、Vue3.0的监听函数、计算函数、普通JS函数 1. Vue的监听函数 Watch监听函数和一些生命周期函数一样,其实就是:给了一个机会,去做一些事情。因此这些函数也通常被称为钩子函数,可以简单理解为某事件触发时把这个时间点钩出来,给了我们一个机会在这个时间点去做一些事。
1.1 (推荐)Watch函数监听ref响应式对象例:
html代码:
<div id="app">
<input v-model="firstName" type="text"/>
<input v-model="lastName" type="text"/>
<div>{{fullName}}div>
div>
JavaScript代码:
const {createApp, ref, watch} = Vue
const firstName = ref('')
const lastName = ref('')
let fullName = ref('')
const app = {
setup() {
// watch函数接收的第一个参数为:要监听的一个响应式对象;
// 第二个参数为:回调函数(在回调函数里面去写我们的业务逻辑)
watch(firstName, (newVal, oldVal) => {
fullName.value = firstName.value + lastName.value
})
watch(lastName, (newVal, oldVal) => {
fullName.value = firstName.value + lastName.value
})
return {
firstName,
lastName,
fullName,
}
}
}
createApp(app).mount('#app')
Watch函数同小程序中的observers:
observers: {
// 单引号内的dataA是this.data中要监听的变量名;括号内的dataA是本监听方法的参数,即该监听变量,命名随意,一般情况下还是与变量名保持相同。
'dataA'(dataA) {
console.log("dataA的当前值为:", dataA)
},
'dataA, dataB'(dataA, dataB) {
console.log("dataA,dataB的当前值为:", dataA, dataB)
},
},
1.2 (不推荐)Watch函数高级用法 - 监听整个reactive响应式对象
例:
html代码:
<div id="app">
<input v-model="name.firstName" type="text"/>
<input v-model="name.lastName" type="text"/>
<div>{{fullName}}div>
div>
JavaScript代码:
const {createApp, ref, reactive, watch} = Vue
const name = reactive({
firstName: '',
lastName: '',
})
let fullName = ref('')
const app = {
setup() {
watch(name, (newVal, oldVal) => {
fullName.value = name.firstName + name.lastName
})
return {
name,
fullName,
}
}
}
createApp(app).mount('#app')
这里解释一下,为什么本例中name是一个const定义的常量,但watch函数还是能监听到name的变化:原因其实官方文档已经解释得很清楚了(上面有图), reactive的响应式转换是“深层”的,它影响所有嵌套的属性。 也就是说,本例中name对象下的firstName属性和lastName属性也被包装成了一个响应式对象。如果对象下还有子对象,子对象下还有子子对象,有多级,那么每一级对象 与 每一级对象下的属性,都会被包装成响应式对象。
1.3 (推荐)监听reactive对象下的单个属性watch函数的第一个参数,除了可以接收一个响应式对象外,还可以接收一个函数。
例:
JavaScript代码:
const {createApp, ref, reactive, watch} = Vue
const name = reactive({
firstName: '',
lastName: '',
})
let fullName = ref('')
const app = {
setup() {
watch(()=>name.firstName, (newVal, oldVal) => {
fullName.value = name.firstName + name.lastName
})
watch(()=>name.lastName, (newVal, oldVal) => {
fullName.value = name.firstName + name.lastName
})
return {
name,
fullName,
}
}
}
createApp(app).mount('#app')
用这种写法可以监听reactive对象下的单个属性。在Vue的文档里,这其实被称之为是一个getter。只想监听reactive对象下的某一个属性,就用这个对象的getter方法,()=>name.firstName
相当于返回了firstName的值。
computed函数会监听函数内所有的变量,如果这些变量发生了变更,那么当前的computed函数就会被再次执行。
例:
html代码:
<div id="app">
<input v-model="firstName" type="text"/>
<input v-model="lastName" type="text"/>
<div>{{fullName}}div>
div>
JavaScript代码:
const {createApp, ref, computed} = Vue
let firstName = ref('')
let lastName = ref('')
const app = {
setup() {
// 用这种方法(computed内传参传的是一个函数),computed计算出来的内容,是只读的,不能被修改的,与const还是let无关。
const fullName = computed(() => firstName.value + lastName.value)
console.log(fullName.value)
return {
firstName,
lastName,
fullName,
}
}
}
createApp(app).mount('#app')
3. 普通JS函数
例:
html代码:
<div id="app">
<input v-model="firstName" type="text"/>
<input v-model="lastName" type="text"/>
<div>{{getFullName()}}div>
div>
JavaScript代码:
const {createApp, ref} = Vue
let firstName = ref('')
let lastName = ref('')
const app = {
setup() {
function getFullName() {
return firstName.value + lastName.value
}
return {
firstName,
lastName,
getFullName,
}
}
}
createApp(app).mount('#app')
以上3者(Watch、Computed、JS函数)的对比
Watch重在监听,看重的是某个变量的变化。使用场景如:监听到某变量的变化后,将此变量保存到服务器。
Computed重在结果,看重的是最终计算出来的结果。使用场景如:拼接姓和名。
Computed和JS函数都可以返回一个结果,从场景的角度来讲,并没有什么区别。但Computed性能会更好一点,因为Computed具备一个计算缓存。任何时候调用普通JS函数,这个函数内的业务逻辑都会再执行一遍,多少会有性能损耗。而Computed内的变量没有变化的话,Computed函数不会再执行一遍,会去计算缓存里读取结果。
综上,优先推荐使用Watch和Computed,这两者使用场景较为明确。
例:
html代码:
<div id="app">
<input v-model="firstName" type="text"/>
<input v-model="lastName" type="text"/>
<div>{{fullName}}div>
div>
JavaScript代码:
const {createApp, ref, computed} = Vue
let firstName = ref('')
let lastName = ref('')
const app = {
setup() {
const fullName = computed({
get: () => firstName.value + lastName.value,
set: (val) => { // 参数名任意
firstName.value = val
}
})
fullName.value = 7 // 这里就相当于set传参传了一个7
return {
firstName,
lastName,
fullName,
}
}
}
createApp(app).mount('#app')
九、创建Vue3项目
1. 用Cli脚手架创建Vue3项目(Cli目前来说还是一个主流)
cli最重要的是可以帮助我们自动构建和打包。
首先 安装npm 并 配置好环境变量,网上教程很多,在此不作赘述。
完成后,在 cmd
小黑窗(命令提示符)里 输入语句 npm -v
,若能成功显示版本号,即为安装成功。
输入语句 npm i -g @vue/cli
安装cli 或 更新cli (如果提示没权限,请在命令的前面加上sudo),稍等片刻后安装完成,输入 vue -V
可以查看版本号,注意 -V
是大写。若能成功显示版本号,即为安装成功。若提示Node版本太低,请自行更新Node。
确保cli安装成功后,进入要创建项目的文件夹,按住 shift
右击,选择 在此处打开命令窗口
,输入语句 vue create 项目名
,如 vue create test
。回车后如图显示:
使用键盘上下键可以选择vue3、vue2,最后一项是手动安装。
待出现下图内容时,即为创建成功。
选择最后一项,手动安装。
下图界面可以手动选择各种各样的特性。如:Vue-router、Vuex(一般建议勾选上这两项)。按键盘上下键移动,敲一下空格键即可选中。选完后回车。此处以默认勾选状态为例:
下图:选择3.x。
下图:选择ESLint规则。本例选择了标准配置:ESLint + Standard config。
注:此处仅作示例!!此项新手慎选!!标准配置可能会出现很多你无法理解的报错!!新手建议选择第一项 ESLint with error prevention only,只有错误时才提醒。
下图:选择Lint on save。
下图:把Eabel,ESLint等等存在哪里。本例选择 存在单独的文件里:In dedicated config files。
下图:将来的项目是否也用该配置。本例输入 n(否)。
待出现下图内容时,即为创建成功。
根目录下(这些我们不用怎么管):
package.json 记录了我们所要依赖的一些npm包。
.eslintrc.js 是 语法 或者说 编码规范 的检测的一个文件。
其他文件大多都是作浏览器兼容性的一些配置。
src文件夹(源码文件夹)下:
我们大多数时候写代码都是在这个src源码目录下面编写。
App.vue 入口文件(也可被看作是一个组件)。打开App.vue可以看到,分为三大块:
评论列表(0条)