Vue 第 1 天 - 初识 Vue 及基础指令
以下内容转载自博主Serein的原创文章,遵循 CC 4.0 BY-SA 版权协议。
视频链接,代码链接 请跳转到下方链接
原文链接:链接在此
一 利其器
学习方法推荐
- 工具学习相对简单,使用场景更重要
- 学习模式「讲一半、练一半」勤动手
- 学完后认真完成作业,讲究学以致用
- 不要强迫性焦虑,练着练着也就会了
- 认真对待企业项目实战,简历中会用
- 坚持刷刷面试经,面试这一关造火箭
二 认识
01- Vue 概述
作者:尤雨溪. 官网:https://cn.vuejs.org
Vue.js 是一套构建用户界面的渐进式框架,采用自底向上增量开发的设计。
渐进式:一步一步,不是说你必须一次把所有的东西都用上
自底向上设计:是一种设计程序的过程和方法,就是先编写出基础程序段,然后再逐步扩大规模、补充和升级某些功能,实际上是一种自底向上构造程序的过程。
Vue 从设计角度来讲,虽然能够涵下图所有的东西,但是你并不需要一上手就把所有东西全用上,都是可选的。声明式渲染和组件系统 是 Vue 的核心库所包含内容,而路由、状态管理、构建工具都有专门解决方案。这些解决方案相互独立,我们可以在核心的基础上任意选用其他的部件,不一定要全部整合在一起。
Vue 仍然是国内最火的框架之一
02 - JS 表达式
[官方文档] https://cn.vuejs.org/guide/essentials/template-syntax.html#%E4%BD%BF%E7%94%A8-javascript-%E8%A1%A8%E8%BE%BE%E5%BC%8F
JS 表达式概念
JS 表达式概念:JS 语句,返回一个值
{{num+1}}
基础运算是表达式
{{isRed?'red':''}}
三元运算符是表达式
{{ const PI=3.141592653}}
const 是声明语句,不是表达式
{ { if }}
、{{ for }}
是逻辑语句,不是表达式,不能直接使用
{{ arr.map( itrm => item) }}
map 是表达式,因为 map 会返回一个新的数组在 Vue 的胡子语法中,可以使用 插值 表达式
<div id="app"> <p>{{msg}}</p> <p>{{num+1}}</p> <p>{{isRed ? 'red' : ''}}</p> </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data() { return { msg: '穷则变,变则通,通则久', num: 1, isRed: false } } }).mount('#app')
三 Vue 内置指令
- Vue 指令 Directives 是带有
v-
前缀的标记性属性标签,交给 Vue 解析其特有的规则- Vue 指令简单来讲,就是 Vue 提供给 HTML 标签新增的自定义属性,代表一定的 Vue 语法意义
- 用法和 HTML 属性一样,但是,一定要注意 自定义指令后 引号内部的是 JS 表达式,会被当做 JS 来进行解析
https://cn.vuejs.org/api/built-in-directives.html
01 - v-text 指令 插入文本内容
v-text 把值作为文本插入到所在的标签之间
Vue 内部是 textContent 实现的
会覆盖掉标签之间的文本
简写
{{}}
,简写用得更多不能解析html
<body> <div id="app"> <p>{{mes}}</p> <!-- 警告提示,在覆盖子标签 --> <!-- <p v-text="mes">被覆盖的</p> --> <p v-text="mes"></p> <!-- 不会解析html --> <p v-text="alink"></p> {{alink}} </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data: () => { return { mes: '学习是一种习惯', alink: '<a href="http://www.baidu.com"> 神奇的网站</a>' } } }).mount('#app') </script> </body>
02 - v-html 指令 插入标签内容
v-html 是把值作为html插入到所在的标签之间,内部实现是 innerHTML,会覆盖标签之间的 html
没有简写
<body> <div id="app"> <!-- 警告提示,在覆盖子标签 --> <!-- <p v-text="mes">被覆盖的</p> --> <p v-html="mes"></p> <!-- 不会解析html --> <p v-html="alink">666</p> {{alink}} </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data: () => { return { mes: '学习是一种习惯', alink: '<a href="http://www.baidu.com"> 神奇的网站</a>' } } }).mount('#app') </script> </body>
03 - v-on 指令快速绑定事件
手册: https://cn.vuejs.org/guide/essentials/event-handling.html
v-on:事件名="事件处理方法"
- 事件处理方法声明在 methods 对象里边,methods,data 并列
- 简写
@事件名="事件处理方法"
当然推荐用简写- 事件名和原生的事件名一致,可以是
dblclick,click,mouseover,keyup,keyenter....
- 事件处理方法的默认参数是
event对象
- 方法传参和原来 HTML 注册事件方法没什么分别
<body> <div id="app"> <input type="button" v-on:click="inputFn" value="点我"> <input type="button" @click="green" value="简写的"> <input type="button" @click="eventFn" value="evnt接收"> <!-- 如果行内传递参数,event也要传递 --> <input type="button" @click="clickFn('来自行内的',$event)" value="传递参数"> </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data: function () { return { mes: '学习是一种习惯', alink: '<a href="http://www.baidu.com"> 神奇的网站</a>' } }, methods: { inputFn() { console.log('在被点击...'); }, green() { console.log('简写也ok'); }, eventFn(e) { console.log(e); }, clickFn(msg, e) { console.log(msg, e); console.log(window.event); } } }).mount('#app')
04 - 简洁方便的事件修饰符
文档: https://cn.vuejs.org/guide/essentials/event-handling.html#event-modifiers
使用方法:
v-on:事件名.修饰符 = "事件处理方法"
<!-- 阻止单击事件继续传播 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件不再重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符可以串联 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只当在 event.target 是当前元素自身时触发处理函数 --> <!-- 即事件不是从内部元素触发的 --> <div v-on:click.self="doThat">...</div> <!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` --> <input v-on:keyup.enter="submit">
<body> <div id="app"> <div @click="fn1" class="one"> <!-- stop 阻止冒泡 --> <div @click.stop="fn2" class="two"></div> </div> <!-- prevent 阻止默认行为 --> <br /> <br /> <a @click.prevent="fn3" href=""> 不动</a> <br /> <br /> <!-- 点击的元素为自身才触发 --> <div @click.self="fn4" class="one"> <div class="two"></div> </div> </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data: function () { return { mes: '学习是一种习惯', alink: '<a href="http://www.baidu.com"> 神奇的网站</a>' } }, methods: { fn1() { console.log('fn1...'); }, fn2() { console.log('fn2...'); }, fn3() { console.log('fn3...'); }, fn4() { console.log('fn4...'); } } }).mount('#app') </script> <style> .one { width: 100px; height: 100px; background: red; } .two { width: 50px; height: 50px; background: green; } </style> </body>
按键修饰符
<body>
<div id="app">
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input type="button" value="按回车触发" @keyup.enter="submit" />
</div>
<script type="module">
import { createApp } from './vue.js';
createApp({
methods: {
submit() {
console.log('按下触发...');
}
}
}).mount('#app')
</script>
</body>
05 - 在 Vue 方法中使用 this 对象
文档:https://cn.vuejs.org/api/options-state.html#methods
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KwxpJjrd-1686666565724)(/assets/img/docs/1665884231907.png)]
方法中的
this
自动绑定为 Vue 实例。
- 方法里面的 this 就是 Vue 实例。
- 方法里面的 this 可以直接访问到 data 的属性和 methods 的方法。
- Vue 里面属性值改变,对应视图将会「响应」我们也叫做响应式对象。
'<body> <div id="app"> <div>{{ message }}</div> <p @click="fn">常常做不怕千万事</p> </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data() { return { message: '扬眉吐气!', hobby: { name: 'zs', age: 22 } } } , methods: { fn() { console.log(this); console.log(this.message); console.log(this.hobby); this.say(); }, say() { console.log('毛主席,斗而不破...'); } } }).mount('#app') </script> </body>
06 - v-bind 指令 动态绑定属性
文档 https://cn.vuejs.org/api/built-in-directives.html#v-bind
v-bind 指令,绑定属性,可以动态绑定 HTML 标签的属性
v-bind 指令的使用
v-bind:属性名="js表达式"
v-bind: src=“imgUrl”
, src 属性绑定到 imgUrl, 改变 imgUrl,会动态改变 src 的值v-bind:可以简写为
:属性名="js表达式"
当然推荐简写
v-bind:class
动态改变 className 进而改变样式
- 三元运算切换样式
- 对象语法
{类名:是否添加样式}
- 可以直接绑定数组多个 className
v-bind:style="js对象"
动态直接改变样式
- 对象的key如果是中划线边连接,建议用字符串或者驼峰
"background-color"
backgroundColor
<body> <div id="app"> <img v-bind:src="img" @click="changeImg"> </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data() { return { img: '../images/10.jpg' } }, methods: { changeImg() { this.img = '../images/12.jpg'; } } }).mount('#app') </script> </body>
<body> <div id="app"> <div :class="bgRed">试探底线</div> <div :class="isRed?'red':''" @click="isRed=!isRed">毫无下限</div> <div :class="{'green':isGreen}" @click="isGreen=!isGreen">统一战线</div> </div> <script type="module"> // import { createApp } from './vue.js'; createApp({ data() { return { bgRed: 'red', isRed: true, isGreen: true } }, }).mount('#app') </script> </body>
<body> <div id="app"> <div style="background: color">努力,努力,在努力</div> <!-- 一次绑定多个class --> <div :class="[classA, classB]">多个class</div> <!-- 注意牵扯到表达式,要带{},里面的值要加 '' --> <div :style="{background:isGreen?'green':'red',color:'skyblue'}"> 奋斗一次,不枉此生 </div> <!-- 自定义属性 --> <div v-bind="{'data-id':gId}">心常用则活,不用则窒</div> </div> <script type="module"> import { createApp } from './vue.js'; createApp({ data() { return { classA: 'one', classB: 'two', isGreen: true, gId: 123 } }, }).mount('#app') </script> </body>
07- Demo 计数器
#### 实现步骤 1. 使用 vue语法 直接绑定响应式对象,用来显示数字 2. 加、减功能的实现,定义点击事件,调用对应方法 3. 数字的范围是 0---10,如果数字超过边界 - 可以动态给 button 按钮添加 disable 属性
<body>
<div id="app">
<input type="button" value="-" :disabled="disStatus" @click="reduce">
<span>{{num}}</span>
<input type="button" value="+" :disabled="incStatus" @click="increase">
</div>
<script type="module">
import { createApp } from './vue.js';
createApp({
data() {
return {
num: 0,
disStatus: false,
incStatus: false,
showClass: false
}
},
methods: {
reduce() {
this.num--
if (this.num == 0) {
this.disStatus = true;
}
this.incStatus = false
},
increase() {
this.num++
if (this.num == 10) {
this.incStatus = true;
}
this.disStatus = false
}
}
}).mount('#app')
</script>
</body>
08- Demo 图片切换
实现步骤
- 做一个数组在 data 中,用来存放图片列表
- 图片显示区域用来展示图片,src 属性 使用 v-bind 进行绑定,初始值为第一张照片
- 点击上一张、下一张两个按钮,绑定执行事件
- 根据事件切换 src 绑定的图片地址
- 到达边界进行逻辑计算,实现循环切换效果
09 - Vue 核心原理理解及原生 JS 实现
声明式渲染,模板引擎
Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统,简单来说,就是在 JavaScript 中写变量,然后,可以通过一定的语法规则,直接渲染到页面上
<body> <!-- 这里本质上来讲是一个 模板引擎 --> <div id="app"> <h2>{{msg}}</h2> <h3>{{info}}</h3> <h3>{{view}}</h3> <h1 v-text="msg"></h1> <h1 v-text="info"></h1> </div> </body> </html> <script> // 首先声明一个 JS 变量,内部包含在 DOM 中可能使用的属性 let data = { msg: "你好,中国!", info:"Vue的本质还是JavaScript!", view: "我是一个页面" } // 获取 id 为 app 下的所有元素的 html 字符串 const bhtml = document.getElementById("app").innerHTML; console.log(bhtml) // 使用正则表达式来进行 replace 关键部分替换 {{}}(胡子语法) const nhtml = bhtml.replace(/{{(.+)}}/g, function(res){ // 使用正则表达式进行匹配 res.match(/{{(.+)}}/g); // 使用 RegExp 来获取匹配到的 () 里面的内容 console.log(RegExp.$1); return data[RegExp.$1]; }); console.log(nhtml) document.getElementById("app").innerHTML = nhtml; data.msg = "我是新的值!" // 使用属性选择器来选择具有 v-text 的元素 var nodes = document.querySelectorAll("[v-text]"); for(let i=0; i< nodes.length; i++){ nodes[i].innerHTML = data[nodes[i].getAttribute("v-text")] } </script>
组件化应用构建,模块复用
组件系统是 Vue 的另一个重要概念(后续学习),因为它是一种抽象的允许我们使用小型、独立和通常可复用的“小积木”构建大型应用,几乎任意类型的应用界面都可以抽象为一个组件树。简单来说,其实就是将一个模块封装为一个函数(对象),然后可以快速的进行复用
<style> .box { width: 200px; height: 200px; background-color: red; } </style> <body> <div id="app"></div> </body> </html> <script> function createComponent(index) { // 创建一个 div 元素 let oneCompoent = document.createElement("div"); // 设置一个 class 为 box 的属性 oneCompoent.setAttribute("class", "box"); // 给当前构建的 div dom 对象添加内部元素 oneCompoent.innerHTML = ` <h1>我是第` + index + `个标题</h1> <p>我是一个段落</p> `; // 获取 id 为 app 元素,添加我们构建的一个 dom 节点 document.getElementById("app").appendChild(oneCompoent) } createComponent(1); createComponent(2); createComponent(3); createComponent(4); createComponent(5); createComponent(6); </script>
响应式数据对象双向绑定
Vue 中使用响应式数据对象声明,进而驱动页面行为。通俗的讲就是:
- 在 js 中修改了数据,在页面中的 DOM 直接就配合进行修改数据
- 同时,在 DOM 表单中用户操作修改了数据,js 中也同步接收这个数据。
vue2的数据绑定
<body> <div id="msg">你好</div> <input type="text" name="" id="" oninput="changeName(this)"> </body> </html> <script> const userinfo = { name: "你好,中国" } const obj = {} // 这就是一个程序公式,按照对应方法调用 Object.defineProperty(obj, "name", { // 每一次读取,都会经过 get ,里面的逻辑都会执行 get(){ document.getElementById("msg").innerHTML = userinfo.name; return userinfo.name; }, // 每一次赋值,都会经过 set,里面的逻辑都会执行 set(name){ userinfo.name = name; document.getElementById("msg").innerHTML = name; } }) console.log(obj.name) obj.name = "这是一个有点忧郁的天!" function changeName(that){ obj.name = that.value; } </script>
vue3 的数据绑定
<body>
<div>
<button>改变uname</button>
<input type="text" name="user" id="user">
<h1></h1>
</div>
<script>
// 页面中数据变化,可以影响js中对象,对象的修改也可以直接影响页面
let userinfo = {
uname: '小甜甜'
}
let proxy = '';
function watcher() {
proxy = new Proxy(userinfo, {
set(target, key, val) {
if (key == 'uname') {
updateDOM(val)
}
}
})
}
watcher();
function updateDOM(val) {
// 修改input和h1中的值
document.querySelector('h1').innerHTML = val;
document.querySelector('input').value = val;
}
// 直接修改对象
document.querySelector('button').onclick = function () {
proxy.uname = '大甜甜';
}
// 给input绑定输入事件
document.querySelector('input').oninput = function () {
// 将input的值设置给userinfo
proxy.uname = this.value;
}
</script>
</body>
10 - 课后作业
- 勤学苦练相关 Vue 指令
- 完成 计数器、图片切换 两个 Demo
- 基于 js 源码来理解 Vue 的一些核心概念(选修)