Vue框架
定义:渐进式 JavaScript 框架
渐进式:可以控制一个页面的一个标签,可以控制一系列标签,也可以控制整个页面,甚至可以控制整个前台项目。
通过对框架的了解与运用程度,来决定其在整个项目中的应用范围,最终可以独立以框架方式完成整个web前端项目
一、Vue基础
1、什么是Vue
可以独立完成前后端分离式web项目的JavaScript框架
2、为什么要学习Vue
三大主流框架之一:Angular(庞大) React(精通移动端) Vue(吸取前两者优势,轻量级)
先进的前端设计模式:MVVM
可以完全脱离服务器端,以前端代码复用的方式渲染整个页面:组件化开发
3、特点
有指令(分支结构,循环结构...),复用页面结构等
有实例成员(过滤器,监听),可以对渲染的数据做二次格式化
有组件(模块的复用或组合),快速搭建页面
单页面web应用
数据驱动
数据的双向绑定
虚拟DOM
4、Vue安装
- 开发版本:vue.js
- 生产版本:vue.min.js
""" 1)cdn导入 2)本地导入 """
注意:
挂载点介绍
el: 挂载点
1)一个挂载点只能控制一个页面结构(优先匹配到的结构)
2)挂载点挂载的页面标签严格建议用id属性进行匹配(一般习惯用app)
3)html标签与body标签不能作为挂载点(html和body标签不可以被替换,组件中详细介绍)
4)是否接受vue对象,是外界是否要使用vue对象的内容决定的
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>挂载点title>
<body>
<div id="app">
<div>
{{ num }}
div>
<div>
{{ num }}
div>
div>
<div id="main">
{{ n }}
div>
body>
<script src="js/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
num:100
}
});
console.log('12345');
console.log(app.num);
// console.log(app.$data.num);
console.log(app.$el);
new Vue({
el: '#main',
data:{
n:app.num
}
})
script>
html>
插值表达式
1)空插值表达式:{{ }}
2)插值表达式中渲染的变量在data中可以初始化
3)插值表达式可以进行简单运算与简单逻辑
4)解决插值表达式符号冲突,用delimiters自定义(了解)
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>插值表达式title>
head>
<body>
<div id="app">
<p>{{ info }}p>
<p>{{ msg }}p>
<p>{{ }}p>
<p>{{ num }}p>
<p>{{ num + 10 * 2 }}p>
<p>{{ msg + num }}p>
<p>{{ msg.length + num }}p>
<p> {{ msg[4] }}p>
<p> {{ msg.split('') }}p>
div>
body>
<script src="js/vue.js">script>
<script>
new Vue({
el: '#app',
data:{
info:'信息',
msg:'message',
num:10
},
// 控制vue插值表达式符号 (了解)
// delimiters: ['[{','}]']
})
script>
html>
过滤器
1)用实例成员filters来定义过滤器
2)在页面结构中,用 | 来标识使用过滤器
3)过滤方法的返回值就是过滤器过滤后的结果
4)过滤器可以对1~n个变量进行过滤,同时还可以传入辅助的变量,
过滤器方法接受参数是按照传入的位置先后
计算属性
"""
计算属性:
1)即vue中的方法属性,就是方法名可以作为属性来使用,属性值为方法的返回值
2)在computed中声明的方法属性,不能在data中重复声明,只是比data中声明的属性要多出写逻辑的地方
3)方法属性自带监听机制,在方法属性中出现的变量都会被监听,一旦有任何被监听的变量值发生更新,方法属性都会被调用,更新方法属性的值
4)方法属性一定要在页面中渲染一次,方法属性才有意义,多次渲染 方法属性只会被调用一次
应用场景:计算器,一个变量依赖于多个变量,且需要进行一定的逻辑运算
"""
<div id="app"> <input type="number" v-model="num1"> + <input type="number" v-model="num2"> = <button>{{ sum }}button> div> <script> new Vue({ el: '#app', data: { // sum: '', // 重复声明 num1: '', num2: '', }, computed: { sum () { // num1和num2都在该方法属性中,所以有一个更新值,该方法都会被调用 if (this.num1 && this.num2) { return +this.num1 + +this.num2; // +this.num1是将字符串快速转换成数字 } return '结果'; } } }) script>
监听属性
"""
1)watch中不定义属性,只是监听属性,所以方法的返回值没有任何意义,只是监听变量值是否发生更新
2)watch中的方法名,就是被监听的属性(方法名同被监听属性名)
3)被监听的变量值一旦发生更新,监听方法就会被调用
应用场景:
i)k线图:股票数据变化,页面的k线图重新渲染(需要逻辑将数据转换为图形)
ii)拆分姓名:录入姓名,拆分为姓和名(需要逻辑将一个数据拆分为多个数据)
"""
<div id="app"> 姓名:<input type="text" v-model="full_name"> <hr> 姓:<button>{{ first_name }}button> 名:<button>{{ last_name }}button> div> <script> new Vue({ el: '#app', data: { full_name: '', first_name: '未知', last_name: '未知' }, watch: { full_name () { if (this.full_name) { // 实现简易的拆分逻辑 this.first_name = this.full_name.split('')[0]; this.last_name = this.full_name.split('')[1]; } else { this.first_name = '未知'; this.last_name = '未知'; } } } }) script>
JS反引号变量占位
"""
1)双引号:
"前缀" + 变量 + "后缀"
2)单引号:
'前缀' + 变量 + '后缀'
3)反引号:
`前缀${变量}后缀`
注:在反引号中可以用 ${} 来包裹变量,实现字符串拼接
"""
基础实例成员
1)el:id选择器
2)data:提供渲染的数据
3、methods:提供绑定的方法
4、filters:提供自定义过滤器,过滤器可以同时过滤多个参数,还可以串联过滤器
5、delimiters:插值表达式标识符,['{{','}}']
指令
1)v-* 是vue指令,会被vue解析,v-text="num"中的num是变量(指令是有限的,不可以自定义)
2)v-text是原样输出渲染内容,渲染控制的标签自身内容会被替换掉(
123
会被num替换)3)v-html可以解析渲染html语法的内容
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>文本指令title>
head>
<body>
<div id="app">
<p>{{ num | add(300) }}p>
<p v-text="num" class="123">p>
<p v-text="num">123p>
<p v-text="info">p>
<p v-html="info">p>
<p v-text="'abc' + num + 10">p>
<p>{{ 'abc' + num + 10 }}p>
div>
body>
<script src="js/vue.js">script>
<script>
new Vue({
el: '#app',
data: {
num:100,
info: 'info内容'
},
filters:{
add:function (a,b) {
return a + b;
}
}
})
script>
html>
事件指令
""" /** * 一、数据驱动 * 1)操作是一个功能,使用需要一个方法来控制 2)方法名是变量,所以控制变量就可以控制该方法 * * * 二、事件指令 * 1)在实例成员methods中声明事件方法 * 2)标签通过事件指令绑定声明的方法: v-on:事件名="事件方法名" * eg: <button v-on:click="btnClick">按钮button> * 3)标签通过事件指令绑定声明的方法,且自定义传参: v-on:事件名="事件方法名()" * eg: <button v-on:click="btnClick()">按钮button> 不传任何参数 * eg: <button v-on:click="btnClick($event)">按钮button> 传入事件对象,同不写() * eg: <button v-on:click="btnClick(10)">按钮button> 只传入自定义参数,当然也可以传入事件对象 */ """
重点:v-on: 可以简写为 @
<body> <div id="app"> <button v-on:click="btnClick">{{ btn1 }}button> <button v-on:click="btnClick">{{ btn2 }}button> <hr> <button v-on:click="fn1">按钮3button> <button v-on:click="fn2($event, 10, 20)">按钮4button> <hr> <button v-on:click="fn(btn1)">{{ btn1 }}button> <button v-on:click="fn(btn2)">{{ btn2 }}button> div> body> <script src="js/vue.js">script> <script> // 对比DOM驱动:1)js选择器获取目标标签 2)为目标标签绑定事件 3)在事件中完成相应逻辑 // var btn = document.getElementsByTagName('button')[0]; // btn.onclick = function () { // console.log(111111111111); // }; new Vue({ el: '#app', data: { btn1: '按钮1', btn2: '按钮2', }, methods: { btnClick () { console.log(666) }, fn1 (ev) { console.log(ev.clientX, ev.clientY); }, fn2(ev, n1, n2) { console.log(ev, n1, n2); console.log(ev.clientX, ev.clientY); }, fn (msg) { console.log(msg); } } }) script>
<style> body { /* 不允许文本选中 */ user-select: none; } .d1:hover { color: orange; /* 鼠标样式 */ cursor: pointer; } /* 只有按下采用样式,抬起就没了 */ .d1:active { color: red; } /* div标签压根不支持 :visited 伪类 */ .d1:visited { color: pink; } .d2.c1 { color: orange; } .d2.c2 { color: red; } .d2.c3 { color: pink; } style> <div id="app"> <div class="d1">伪类操作div> <br><br><br> <div :class="['d2', c]" @click="hFn('c1')" @mouseover="hFn('c2')" @mousedown="hFn('c3')">事件处理div> div> <script> new Vue({ el: '#app', data: { c: '', }, methods: { hFn (c) { this.c = c } } }) script>
斗篷指令
v-cloak:避免屏幕闪烁
1)属性选择器,会将v-cloak属性所在的标签隐藏
2)当vue环境加载后,会将v-cloak属性解析移除,所以内容{{ num }}就会显示出来
3)而现在vue已经准备完毕,所以用户会直接看到数值10,而不会看到 页面从{{ num }}闪烁成数值10 """
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>title>
<style>
[v-cloak] {
display: none;
}
style>
head>
<body>
<div id="app" v-cloak>
<p>{{ num }}p>
div>
body>
<script src="js/vue.js">script>
<script>
new Vue({
el: '#app',
data:{
num:10
},
})
script>
html>
属性指令
属性指令 1)语法:v-bind:属性名="变量" 2)针对不同属性,使用方式稍微有区别 i)自定义属性以及title这些,直接赋值的,使用方式如下(t是变量,'o'是常量) <p v-bind:title="t" v-bind:owen="'o'">段落p> ii)class属性(重点): 绑定的变量:值可以为一个类名 "p1",也可以为多个类名 "p1 p2" 绑定的数组:数组的每一个成员都是一个变量 绑定的字典:key就是类名,value是决定该类名是否起作用的
iii)style属性(了解):
绑定的变量:值是一个字典
重点:
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>属性指令title>
<style>
.b1 {
width: 100px;
height: 100px;
background-color: red;
}
.b2 {
border-radius: 50%;
}
style>
head>
<body>
<div id="app">
<p v-bind:class="a" style="color: red;background-color:orange " v-bind:title="t" v-bind:owen="'o'">段落p>
<p v-bind:class="b">p>
<p class="b1 b2">p>
<p v-bind:class="[c,d]">p>
<p v-bind:class="{b1:0}">p>
<p v-bind:class="[a,{b1:e}]">p>
div>
body>
<script src="js/vue.js">script>
<script>
new Vue({
el: '#app',
data:{
t:'悬浮提示',
a:'a1',
b:'b1 b2',
c:'b1',
d:'b2',
e:true,
}
})
script>
html>
<p v-bind:style="myStyle">p> <script> let app = new Vue({ el: '#app', data: { myStyle: { width: '50px', height: '50px', backgroundColor: 'pink', borderRadius: '50%' } }, }) script>
案例:
<style> .live{ background-colorL:yellowgreen } style> <button v-bind:class="{live: isLive == 1}" v-on:click="changeLive(1)">1button> <button v-bind:class="{live: isLive == 2}" v-on:click="changeLive(2)">2button> <button v-bind:class="{live: isLive == 3}" v-on:click="changeLive(3)">3button> <script> let app = new Vue({ el: '#app', data: { isLive: 0, }, methods: { changeLive (index) { // this就代表当前vue对象,和app变量等价 // app.isLive = index; this.isLive = index; } } }) script>
表单指令
1)语法:v-model="变量"
2)v-model绑定的变量控制的是表单元素标签的value属性值
3)v-model要比v-bind:value要多一个监听机制
4)数据的双向绑定:
v-model可以将绑定的变量值映射给表单元素的value
v-model还可以将表单元素的新value映射给表单的变量
<div id="app"> <form action="" method=""> <input name="n1" type="text" v-model="v1"> <input name="n2" type="text" v-model="v1"> <button type="submit">提交button> form> div> <script> new Vue({ el: '#app', data: { v1: '' } }) script>
条件指令
1)语法:v-show="变量" | v-if="变量"
2)两者区别:
v-show在隐藏标签时,采用display:none渲染标签,标签通过css隐藏
v-if在隐藏标签时,不会渲染到页面上
3)v-if有家族:v-if | v-else-if | v-else
v-if是必须的,必须设置条件
v-else-if可以为0~n个,必须设置条件
v-else可以为0~1个
上方分支成立会屏蔽下方所有分支,从上到下依次类推
<div id="app"> <div> <p v-show="isShow">show控制显隐p> <p v-if="isShow">if控制显隐p> div> <div> <p v-if="1">你是第一个pp> <p v-else-if="2">你是第二个pp> <p v-else>你是第三个pp> div> div> <script> new Vue({ el: '#app', data:{ isShow:false, } }) script>
案例:
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>案例title>
<style>
body {
margin: 0
}
button {
width: 60px;
line-height: 40px;
float: right;
}
.bGroup:after {
display: block;
content: '';
clear: both;
}
.box {
/* vw: view width vh: view height*/
width: 100vw;
height: 200px;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: blue;
}
button.active {
background-color: cyan;
}
style>
head>
<body>
<div id="app">
<div class="bGroup">
<button :class="{active: isShow === 'red'}" @click="isShow = 'red'">红button>
<button :class="{active: isShow === 'green'}" @click="isShow = 'green'">绿button>
<button :class="{active: isShow === 'blue'}" @click="isShow = 'blue'">蓝button>
div>
<div>
<div v-if="isShow === 'red'" class="box red">div>
<div v-else-if="isShow === 'green'" class="box green">div>
<div v-else class="box blue">div>
div>
div>
body>
<script src="js/vue.js">script>
<script>
new Vue({
el: '#app',
data: {
isShow: 'red'
}
})
script>
html>
循环指令
"""
1)语法:v-for="ele in obj" obj是被遍历的对象,ele是遍历得到的每一次结果
2)遍历可迭代对象的首要结果,都是可迭代对象容器中的值,其次还可以遍历得到索引及键等数据
字符串:v-for="v in str" | v-for="(v, i) in str"
数组:v-for="v in arr" | v-for="(v, i) in arr"
对象:v-for="v in obj" | v-for="(v, k) in obj" | v-for="(v, k, i) in obj"
注:v-for遍历要依赖于一个所属标签,该标签及内部所有内容会被遍历复用
"""
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>循环指令title>
head>
<body>
<div id="app">
<p>{{ d1 }}p>
<i v-for="e in d1">【{{ e }}】i>
<hr>
<p>{{ d2 }}p>
<i v-for="e in d2">【{{ e }}】i>
<i v-for="(e, i) in d2">【{{ i }}{{ e }}】i>
<hr>
<p>{{ d3 }}p>
<i v-for="e in d3">【{{ e }}】i>
<i v-for="(e, i) in d3">【{{ i }}{{ e }}】i>
<hr>
<p>{{ d4 }}p>
<i v-for="e in d4">【{{ e }}】i>
<i v-for="(e, k) in d4">【{{ k }}-{{ e }}】i>
<i v-for="(e, k, i) in d4">【{{ k }}-{{ e }}-{{ i }}】i>
<hr>
div>
body>
<script>
new Vue({
el: '#app',
data: {
d1: 5,
d2: 'abc',
d3: [1, 3, 5],
d4: {
name: "Bob",
age: 17.5,
gender: "男"
}
}
})
script>
案例:
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>title>
<style>
.box {
width: 280px;
border: 1px solid #eee;
border-radius: 5px;
overflow: hidden; /* 隐藏超出父级显示范围外的内容 */
text-align: center; /* 文本相关的属性大多默认值是inherit */
float: left;
margin: 10px;
}
.box img {
width: 100%;
}
style>
head>
<body>
<div id="app">
<div class="box" v-for="obj in goods">
<img :src="obj.img" alt="">
<p>{{ obj.title }}p>
div>
div>
body>
<script src="js/vue.js">script>
<script>
let goods = [
{
"img":"https://***1.jpg",
"title": "商品1"
},
{
"img":"https://***2.jpg",
"title": "商品2"
}
];
new Vue({
el:"#app",
data:{
goods,
}
})
script>
html>
todolist
补充知识点:
js的Array操作
"""
尾增:arr.push(ele)
首增:arr.unshift(ele)
尾删:arr.pop()
首删:arr.shift()
增删改插:arr.splice(begin_index, count, args)
"""
前台数据库
"""
// 存
// 持久化化存储,永远保存
localStorage.name = "Bob";
// 持久化化存储,生命周期同所属标签(页面),页面关闭,重新打开就会丢失
sessionStorage.name = "Tom";
// 取
console.log(localStorage.name);
console.log(sessionStorage.name);
// 清空
localStorage.clear();
sessionStorage.clear();
// 短板:只能存储字符串,所以对象和数组需要转换为json类型字符串,再进行存储
let a = [1, 2, 3];
localStorage.arr = JSON.stringify(a);
let b = JSON.parse(localStorage.arr);
console.log(b);
"""
splice:
案例:留言板
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>todolisttitle>
<style>
li:hover {
color: red;
cursor: pointer;
}
style>
head>
<body>
<div id="app">
<form action="">
<input type="text" v-model="info">
<button type="button" @click="sendInfo">留言button>
form>
<ul>
<li v-for="(info,index) in info_arr" @click="deleteInfo(index)">{{ info }}li>
ul>
div>
body>
<script src="js/vue.js">script>
<script>
new Vue({
el: '#app',
data:{
info:'',
// 三元运算符: 条件 ? 结果1 : 结果2
info_arr:localStorage.info_arr ? JSON.parse(localStorage.info_arr) : []
},
methods: {
sendInfo() {
//完成留言,将info添加到info_arr
// 增 push unshift | 删 pop shift
if(this.info){
//留言
this.info_arr.push(this.info);
//清空输入框
this.info = '';
//前台数据持久化(缓存)
localStorage.info_arr = JSON.stringify(this.info_arr);
}
},
deleteInfo(index){
// 删留言
this.info_arr.splice(index,1)
// 同步给数据库
localStorage.info_arr = JSON.stringify(this.info_arr);
}
}
})
script>
html>
"""1)双引号:"前缀" + 变量 + "后缀"2)单引号:'前缀' + 变量 + '后缀'
3)反引号:`前缀${变量}后缀`注:在反引号中可以用 ${} 来包裹变量,实现字符串拼接"""