前言
新的一年,在这里就先祝大家兔年大吉吧!一直想写点东西,但总是定不下心来,今年痛下决心写点东西,主要记录我的学习过程,帮助新来的同学做个梳理和参考。今年的目标:希望能完成三个系列《Vue速成》、《Flutter》、《Nodejs》。 这些系列会更偏向于渐进式的操作,库的使用等。语言基础和理论方面的知识应该会比较少,原因有二:1、理论比较枯燥,本系列主要是针对有一定语言基础的新手,主要的应该以操作为主,这样更能提高阅读的性质。2、由于本人的理论基础有限,不希望给读者造成错误的引导;当然一些需要了解的理论知识也有可能会外链引用到其他大佬的文章!
vue基础
那么从这里开始我们默认你是有一些html、js、css基础的。本篇会比较啰嗦,主要是针对vue 0基础。大部分读者可跳过!!!
案例演示前置说明
下列的案例均是以传统的
html静态页面引入Vue version2.*进行演示,之所以这样选用的原因说明:
- 我们打开
vue官网看到的第一句话就是vue是一个渐进式 的JavaScript框架,那么我们也应该通过渐进式的演示在静态页面中vue的使用过程,而不直接使用脚手架、打包工具进行编写,这样更有利于我们进行了解和学习 - 使用
vue2是因为目前市面上大部分的项目依然是是vue2的写法,开始我们就使用这样的写法会使我们更对旧的写法有所熟悉和了解,后续使用到脚手架后我们会慢慢的转向vue3的方式
1)创建vue实例
- 1、通过cdn引用
vue2的库文件
<!--引入vue库文件-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
- 2、创建一个我们需要
vue进行管理的局域(容器),并且指定唯一id值
<div>这是在vue管理的实例之外的内容区域</div>
<div id="app">
<!--#app内的区域将作为一个vue实例的掌管区域-->
</div>
- 3、
new一个Vue实例,并且绑定到第2步的容器上,此时该容器内的Vue将能接管该实例内的逻辑
<div>这是在vue管理的实例之外的内容区域</div>
<div id="app">
<!--#app内的区域将作为一个vue实例的掌管区域-->
</div>
<script>
new Vue({
el: "#app", // 绑定到该页面上的"#app"上
})
</script>
2)data选项的使用 html中使用到对应的vue实例的数据
- 1、创建
data选项数据;Vue类接收一个对象,对象的key值有固定的写法,要详细了解需通过官网文档查看,此处我们首先介绍data选项,他应该是一个函数,并且函数内必须返回一个对象,返回的对象的数据均是响应式的数据。- 为什么是一个函数的原因参考:vue 组件的 data 为什么必须是函数
- 为什么是一个函数的深入原理参考:JS引用类型梳理
<div>这是在vue管理的实例之外的内容区域</div>
<div id="app">
<!--#app内的区域将作为一个vue实例的掌管区域-->
</div>
<script>
new Vue({
el: "#app", // 绑定到该页面上的"#app"上
data() {
return {
message: "这是自动响应的数据"
}
}
})
</script>
3)使用Vue实例的响应数据
<div>这是在vue管理的实例之外的内容区域</div>
<div id="app">
<!--#app内的区域将作为一个vue实例的掌管区域-->
<!--在标签内使用vue中的数据或者函数可使用"{{}}"双花括号进行包裹,花括号内的内容会被vue进行接管替换,并且this指向当前区域对应的vue实例-->
<div class="msg1">{{this.message}}</div>
<!--由于我们会经常使用到实例的数据,vue为我们的省略this,直接写message也是可以的-->
<div class="msg2">{{message}}</div>
</div>
<script>
new Vue({
el: "#app", // 绑定到该页面上的"#app"上
data() {
return {
message: "这是自动响应的数据"
}
}
})
</script>
关于
响应式数据这是一个很重要的概念,是学习类似vue这些mvvm框架的核心思想,初学者一定要时刻提醒自己记住以下几点,这是快速学好vue的核心。
- 1、
响应式数据简单理解就是:当数据发生变化的时候,视图是根据数据进行自动响应变化的,当数据发生变化了,vue框架会帮我自动的改变视图界面。 - 2、我们千万不要试图去自行的操作html dom节点(当你存在这种想法的时候,在武侠小说里就是
准备走火入魔了),这样会导致视图界面与数据不统一。(例:上面的例子,当我们试图通过innerText的方式去改变div.msg2内的文字时,这是视图中的内容会与对应的vue实例的data中的message的内容中是不一致的,这可能会导致很严重的bug。比如上面的div.msg1和div.msg2引用的是同一个数据,那么他应该永远是保持一致的) - 3、那么如何控制界面的变化呢?在vue里面我们要有一个
数据驱动的思想。(我们只需要搭好界面,将界面关联到对应的数据即可,后续当我们需要改动某些界面的时候,我们只需要操作改界面绑定的数据即可,至于界面的变动则交由vue框架去自行变动。) - 4、
数据驱动即:通过操作数据去驱动界面的变化。下列是一些理论的补充参考:
<div id="action">
<div>{{msg}}{{timeMsg}}</div>
<div>
<!-- v- 开头的都是vue的指令包含内置指令、自定义指令-->
<!-- v-on: 给元素绑定事件监听器。-->
<!-- v-on:click 给元素绑定点击事件监听器。-->
<!-- v-on:click="setTime" 给元素绑定点击事件监听器,触发后调用vue实例的方法,方法需要在methods选项中创建。-->
<button v-on:click="setTime">设置当前时间戳</button>
<!-- 由于v-on经营使用,官方提供了简写"@"符号。-->
<!-- 时间触发后应该传入一个函数,函数如果不需要特殊的参数则可省略(),如果需要自定义参数,则可如changeMsg('时间:','00:00')的形式进行传入-->
<!-- v-on (@)修饰后的事件属性的值接收的是js语法的函数,也可写行内的箭头函数-->
<button @mouseup="changeMsg('时间:','00:00')">改变提示文本内容</button>
<button @click="reset">还原数据</button>
</div>
</div>
<script>
const defaultMsg = "默认内容:"
new Vue({
el: "#action",
data() {
return {
msg: defaultMsg,
timeMsg: "",
}
},
methods: {
changeMsg(newMsg, timeMsg = "") { // 接收用户输入的变量值
this.msg = newMsg;
},
setTime() {
this.timeMsg = String(Date.now())
},
reset(e) {
// 默认传入的 Event
console.log(e)
this.msg = defaultMsg;
this.timeMsg = "";
}
}
})
</script>
4)Vue中获取和设置input表单元素的值(数据双向绑定的实现)
数据的双向绑定是表单中经常使用到的,一般是指当我们改变数据,绑定该数据的视图会立即响应;表单中用户输入的数据也可以同步的改动到对应的数据。快捷的方式是使用vue
提供的v-model实现,本例是解释实现v-model的过程
- 1、使用
v-bind将相应数据绑定到<input/>的value属性上 - 2、使用
v-on监听<input/>的input事件,实时的获取到用户输入的值并将它覆盖相应数据,从而实现数据的双向绑定
<div id="input">
<div>
<!-- v-bind: 给元素的属性绑定数据 参考文档:https://v2.cn.vuejs.org/v2/api/#v-bind -->
<!-- 通过@input给input元素绑定input事件,可以监听到input的用户输入值的变化 -->
<input v-bind:value="value" @input="onChange"/>
<!-- 由于v-bind经常使用,官方提供了简写":"符号。-->
<input :value="value" @input="onChange"/>
</div>
<div>
<button @click="onClear">清空input的值</button>
</div>
</div>
<script>
new Vue({
el: "#input",
data() {
return {
value: "默认值",
}
},
methods: {
onChange(inputEvent) {
// 取到当前input的文本值,并设置到当前vue实例value上
this.value = inputEvent.target.value
},
// 清空数据
onClear() {
this.value = ""
}
}
})
</script>
5)通过v-model指令实现表单数据的双向绑定
v-model是vue官方提供的一个快捷指令,大大的方便了我们处理类似的用户数据
<div id="model">
<div>
<h3>{{value}}</h3>
<!-- v-model: 在表单控件或者组件上创建双向绑定(即是上例的快捷写法) 参考文档:https://v2.cn.vuejs.org/v2/api/#v-model -->
<input v-model="value"/>
</div>
<div>
<button @click="onClear">清空input的值</button>
</div>
</div>
<script>
new Vue({
el: "#model",
data() {
return {
value: "默认值",
}
},
methods: {
// 清空数据
onClear() {
this.value = ""
}
}
})
</script>
6)v-html指令的使用
通常使用
{{}}显示数据时,默认会对字符串数据原样输出。如果需要显示html片段时会使用到该指令,但是需要注意的XSS攻击
<div id="html">
<div>
<!-- 原样输出 -->
<div>{{value}}</div>
<!-- v-html解析字符串中的html标签,显示html片段 -->
<div v-html="value"></div>
</div>
</div>
<script>
new Vue({
el: "#html",
data() {
return {
value: "<h4 style='color:red'>这是一段红色的标题4的文字</h4>",
}
},
})
</script>
7)v-show指令的使用
v-show用于隐藏、显示某个html元素,该元素会进行渲染,并且使用css的display:none;进行控制隐藏和显示;当遇到某一个html元素需要频繁的更换显隐状态时,应该使用v-show指令进行控制,仅会在首次进行一次渲染。
8)v-if等条件判断指令的使用
v-if相比于v-show
的区别是,会根据条件进行变动时,对dom节点进行移除和添加操作,故在元素状态变换不频繁的情况下使用该指令会比较合适;同时v-if
还会结合
v-else-if和v-else进行使用
9)key的作用
* ```key```在```vue```中作用类似于```html```中的```id```,主要用于```虚拟dom```中```同级别、同标签```的节点更新比较。
*
当某一个新的节点和旧的节点被判定为同一个元素节点时,vue会尽量的复用该节点,而不是进行销毁再渲染;具体的表现为:www.zhihu.com/question/61…
* 什么时候使用key?1.通常在v-for循环的项目中、2.页面中多个资源标签(比如多个<img/>、<video/>
标签)时使用,想通的标签应该使用唯一id作为key。不建议使用v-for得到的下标索引作为key
10)v-for循环指令的使用
循环遍历指令,参考:v2.cn.vuejs.org/v2/api/#v-f…
<div id="for">
<div>
<template v-for="(value,index) in data">
<div v-if="value>0" :key="value">
仅显示value大于0的值:index=>{{index}},value=>{{value}}
</div>
</template>
</div>
</div>
<script>
new Vue({
el: "#for",
data() {
return {
data: [0, 1, 2, 3],
}
},
})
</script>
11)v-bind的补充与计算属性computed选项的使用
* ```v-bind```对象补充主要是演示```class```与```style```
的绑定设置(仅当我们的类样式或者行内样式需要依赖于某些响应数据而动态的变化时,需要使用此种写法);[详细文档参考](https://v2.cn.vuejs.org/v2/guide/class-and-style.html)
* 计算属性```computed```通常会在我们需要对某些相应数据进行加工扩展时使用。生成的数据可直接使用,与```methods```
选项的区别如下:
* ```methods```是函数的形式,生成的数据结果不会进行缓存,每一次调用都会执行一次扩展逻辑。
* ```computed```只有依赖的数据发生变化,才会重新执行扩展逻辑,生成的数据默认提供了```getter```修饰,可以向普通的实例属性一样使用
* ```computed```如果需要提供```setter```,格式写法会有所变化(一般情况下比较少用,此处不做介绍)
<div id="computed">
<div>
<div style="font-weight: bold">1、v-bind绑定的属性值是可以简写简单的js语法的,如下通过三种形式设置类样式:</div>
<div :class="`wrap-bg ${isChecked?'checked':''}`">v-bind:class=`wrap-bg ${isChecked?'checked':''}`字符串的形式
</div>
<div :class="['wrap-bg',isChecked?'checked':'']">v-bind:class=['wrap-bg',isChecked?'checked':'']数组的形式</div>
<div :class="{'wrap-bg':true}">v-bind:class={"wrap-bg":true}对象形式</div>
<div style="font-weight: bold">2、v-bind绑定的style,可通过如下的对象的形式进行设置:</div>
<div :style="{background:'red',color:'white',margin:'10px'}">
v-bind:style="{background:'red',color:'white',margin:'10px'}"设置红色背景,白色的字体和10px填充
</div>
<div style="font-weight: bold">3、计算属性computed的应用:</div>
<div>{{wrapClassMessage}}</div>
<div @mousedown="onWrapDown" @mouseup="onWrapUp" :class="wrapClass">
长按看效果
</div>
</div>
</div>
<script>
new Vue({
el: "#computed",
data() {
return {
isChecked: false
}
},
computed: { // 计算属性选项
/**
* 1、计算属性可以,可以想相应数据data一样直接通过this.*直接引用
* 2、计算属性内部一般都会依赖于某一个或者多个data相应数据(或props数据)后扩展生成的
* 3、计算属性一般是缓存在内存中,仅当依赖的数据发生变化时才会重新组合
* @returns {string[]}
*/
wrapClass() {
const classNames = ['computed-wrap'];
if (this.isChecked) { // 比如此处的wrapClass依赖了this.isChecked,当this.isChecked发生变化时,该计算属性会自动的生成新的值
classNames.push('checked')
}
return classNames;
},
// 计算属性不仅仅可以依赖data,也能同时依赖其他的computed或者props(props后续会讲到,本章节暂时忽略)
wrapClassMessage() {
return `当前的类样式为:${this.wrapClass.join(' ')}`
}
},
methods: {
// 鼠标按下,设置选中状态为真
onWrapDown() {
this.isChecked = true
},
// 鼠标抬起,设置选中状态为假
onWrapUp() {
this.isChecked = false
},
}
})
</script>
<style>
.wrap-bg {
background: coral;
color: white;
margin: 5px 0;
}
.computed-wrap {
width: 100px;
height: 100px;
background: aqua;
cursor: pointer;
}
.computed-wrap.checked {
background: coral;
}
</style>
12)使用watch选项进行数据的监听
* ```watch```可以监听到```data```、```computed```和```props```
的变化(props后续会讲到,本章节暂时忽略),[文档参考](https://v2.cn.vuejs.org/v2/api/#watch)
* 当我们需要监听某个数据发生变化后需要做某些操作(比如调用某个或者多个函数```methods```时)应该使用```watch```进行处理
*
注:当我们需要生成一个新的数据,这个数据依赖于另一个数据(即即另一个数据发生变化时需要重新生成)时应该考虑使用计算属性computed
而不是使用监听器watch!!!
<div id="watch">
<div>
<div style="font-weight: bold">打开控制台,然后点击下列"num++"按钮,查看输出的监听到的值的变化效果</div>
<div>num的值:{{num}}</div>
<div>计算属性powNum的值:{{powNum}}</div>
</div>
<div>
<button @click="onPlus">num++</button>
</div>
</div>
<script>
new Vue({
el: "#watch",
data() {
return {
num: 0
}
},
computed: { // 计算属性选项
powNum() {
return Math.pow(this.num, 2);
},
},
watch: {
// 监听data数据的变化
num(newValue, oldValue) {
console.log(`num:${oldValue} => ${newValue}`)
},
// 也可以监听计算属性的变化
powNum(newValue, oldValue) {
console.log(`powNum由:${oldValue} => ${newValue}`)
}
},
methods: {
onPlus() {
this.num++
},
}
})
</script>
13)v-on的修饰符补充
* ```v-on```
修饰的函数可以使用一些快捷修饰符实现常用的功能,比如禁止事件冒泡、获得焦点的元素监听键盘事件等,并且多个修饰符可以同时使用,例:```<button @click.stop.self.prevent="">这是一个按钮</button>```
<div id="event">
<div>
<div style="color: red">1、默认存在事件冒泡时(点击小框,大框也会接收到点击事件)</div>
<div @mousedown="onWrapDown" @mouseup="onWrapUp" :class="wrapClass">
<div @mousedown="onChildDown" @mouseup="onChildUp" :class="childClass">
长按看效果
</div>
</div>
<div style="color: red">.stop禁止事件冒泡(点击小框,大框并不会收到点击事件)</div>
<div>wrapClass: {{wrapClass}}</div>
<div>childClass: {{childClass}}</div>
<div @mousedown="onWrapDown" @mouseup="onWrapUp" :class="wrapClass">
<div @mousedown.stop="onChildDown" @mouseup.stop="onChildUp" :class="childClass">
长按看效果
</div>
</div>
</div>
</div>
<script>
new Vue({
el: "#event",
data() {
return {
wrapChecked: false, // 是否按下大框
childChecked: false, // 是否按下小框
}
},
computed: {
// 大框使用的类名
wrapClass() {
const names = ['event-wrap'];
if (this.wrapChecked) { // 当按下时大框附加.checked
names.push('checked')
}
return names;
},
// 小框使用的类名
childClass() {
const names = ['event-child'];
if (this.childChecked) { // 当按下时小框框附加.checked
names.push('checked')
}
return names;
},
},
methods: {
// 按下大框
onWrapDown() {
this.wrapChecked = true
},
// 按下小框
onChildDown() {
this.childChecked = true
},
// 鼠标从大框抬起
onWrapUp() {
this.wrapChecked = false
},
// 鼠标从小框抬起
onChildUp() {
this.childChecked = false
}
}
})
</script>
<style>
.event-wrap {
width: 100px;
height: 100px;
background: aqua;
cursor: pointer;
}
.event-child {
width: 50px;
height: 50px;
background: antiquewhite;
cursor: pointer
}
.event-wrap.checked {
background: darkturquoise;
}
.event-child.checked {
background: coral;
}
</style>
14)ref与$nextTick方法的应用
* ```ref```是vue中设置到dom元素的一个特殊属性,当取到一个一个```dom节点```或者```vue组件```的```ref```
就相当于取到了该节点的```引用```。取到ref引用后可以获取该节点或者组件上的实例属性(数据),或者调用存在的方法
* 我们知道vue是一个```数据驱动```
的框架,即:```我们不需要操控dom节点的变化,我们应该操作数据,然后由框架自行操作dom的变动```
,那么从数据发生变化到界面渲染发生变动的这个过程是需要```一定时间```
的,这个时间我们是不可知的。故:当我们需要在操作数据之后,需要在这个数据影响的界面发生变动完成后,及时的获取到这个界面的dom的变化,或者需要再变动完成之后再进行某一事,那么应该考虑使用```$nextTick```
<div id="ref">
<div>
<div style="font-weight: bold">打开控制台,然后点击下列"num++"按钮,查看输出的num值是否统一</div>
<div>
num的值:
<!-- 给span设置一个ref引用,名为:numSpan -->
<span ref="numSpan" style="color: red">{{num}}</span>
</div>
</div>
<div>
<button @click="onPlus">num++</button>
</div>
</div>
<script>
new Vue({
el: "#ref",
data() {
return {
num: 0
}
},
methods: {
onPlus() {
this.num++
console.log("==================分割线=====================")
console.log('当前的num数据:', this.num)
// 通过this.$refs获取实例上的所有ref引用(此处输出的内容是正确的,是因为numSpan是引用类型)
console.log('numSpan:', this.$refs.numSpan)
// 取到名为:numSpan的引用后就可以获取他的属性了(这里输出的内容还是就的值是因为,取出innerText的时期,界面还未重新渲染完成)
console.log('当前界面上的实际内容:', this.$refs.numSpan.innerText)
this.$nextTick(() => {
console.log('$nextTick重新渲染完成后的文本内容:', this.$refs.numSpan.innerText)
})
},
}
})
</script>
结语
本章节是第一篇写的,比较匆忙,文笔生涩。欢迎提点,我会及时的就行修正
章节中的例子完整案例源码 ,如果是初学者还是建议自己动手编写更佳。后续计划预计编写的章节目录