HTML(5)、CSS(3)、JavaScript(ES5、ES6):编写一个个的页面 -> 给后端(PHP、Python、Go、Java) -> 后端嵌入模板语法 -> 后端渲染完数据 -> 返回数据给前端 -> 在浏览器中查看
Ajax的出现 -> 后台发送异步请求,Render+Ajax混合
单用Ajax(加载数据,DOM渲染页面):前后端分离的雏形
Angular框架的出现(1个JS框架):出现了“前端工程化”的概念(前端也是1个工程、1个项目)
React、Vue框架:当下最火的2个前端框架(Vue:国人喜欢用,React:外国人喜欢用)
移动开发(Android+IOS) + Web(Web+微信小程序+支付宝小程序) + 桌面开发(Windows桌面):前端 -> 大前端
一套代码在各个平台运行(大前端):谷歌Flutter(Dart语言:和Java很像)可以运行在IOS、Android、PC端
在Vue框架的基础性上 uni-app:一套编码 编到10个平台
在不久的将来 ,前端框架可能会一统天下
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
渐进式框架:可以一点一点地使用它,只用一部分,也可以整个工程都使用它
官方网站
官网:https://cn.vuejs.org/
文档:https://cn.vuejs.org/v2/guide/
引入
可以直接打开 https://cdn.jsdelivr.net/npm/vue/dist/vue.js 复制源码即可,也可以使用官方提供的 cdn
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
Vue特点
三层
MVVM 是 Model-View-ViewModel 的简写。它本质上就是 MVC 的改进版。
优点
组件化开发
单页面开发
<div id="app">
{{ message }}
div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
可以检测到变动的数组操作:
操作 | 说明 |
---|---|
push | 最后位置添加 |
pop | 最后位置删除 |
shift | 第一个位置删除 |
unshift | 第一个位置添加 |
splice | 切片 |
sort | 排序 |
reverse | 反转 |
检测不到变动的数组操作:
操作 | 说明 |
---|---|
filter() | 过滤 |
concat() | 追加另一个数组 |
slice() | |
map() |
原因:作者重写了相关方法(只重写了一部分方法,但是还有另一部分没有重写)
解决方法:
// 方法1:通过 索引值 更新数组(数据会更新,但是页面不会发生改变)
vm.arrayList[0]
"Alan"
vm.arrayList[0]='Darker'
"Darker"
// 方法2:通过 Vue.set(对象, index/key, value) 更新数组(数据会更新,页面也会发生改变)
Vue.set(vm.arrayList, 0, 'Darker')
Vue.set(vm.obj, 'gender', '未知') # 对象
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
数据绑定最常见的形式就是使用 Mustache 语法 {{}}
(双大括号)的文本插值
Mustache 标签 {{}}
将会被替代为对应数据对象上的值。若绑定的数据对象的值发生了改变,插值处的内容都会更新。
...
<div id="app">
<p>{{ message }}p>
<p>{{ age }}p>
<p>{{ l }}p>
<p>{{ l[0] }}p>
<p>{{ o }}p>
<p>{{ o.name }}p>
<p>{{ o["pwd"] }}p>
<p>{{ u }}p>
<p>{{ score > 60 ? "及格" : "不及格" }}p>
div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
age: 18,
l: [1, 2, 3],
o: {name: 'xwx', pwd: 12},
u: '百度一下 你就知道',
score: 99,
}
})
script>
...
将数组、对象、标签在前端展示都是字符串的格式,例如链接标签不能点击访问等等
还可以在模版语法中添加简单的 js 语法。例如示例中的三目运算符。
修改值
我们可以在 Console 中修改查看效果,修改的方式可以如下方式
指令 | 说明 |
---|---|
v-text | 把字符串原封不动显示在标签上 |
v-html | 把标签字符串渲染后,显示在标签里 |
v-show | 显示与不显示 :style=“display: none;” |
v-if | 显示与不显示,直接将标签删除 |
通过使用 v-once 指令,也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定
<p v-once>{{ message }}p>
<div id="app">
<p>{{u}}p>
<p v-text="u">p>
<p v-html="u">p>
div>
<script>
var app = new Vue({
el: '#app',
data: {
u: '百度一下 你就知道',
}
})
script>
<div id="app">
<p>{{u}}p>
<p v-show="true">{{u}}p>
<p v-show="i">{{u}}p>
<p v-if="true">{{u}}p>
<p v-if="i">{{u}}p>
div>
<script>
var app = new Vue({
el: '#app',
data: {
u: '百度一下 你就知道',
i: false,
}
})
script>
指令 | 说明 |
---|---|
v-if | 用于条件性地渲染一块内容 |
v-else-if | 充当 v-if 的 else-if 块 ,可以连续使用 |
v-else | 表示 v-if 的 else 块 |
v-if、v-else-if、v-else
<div id="app">
<div v-if="type === 'A'">
A
div>
<div v-else-if="type === 'B'">
B
div>
<div v-else-if="type === 'C'">
C
div>
<div v-else>
Not A/B/C
div>
div>
<script>
var app = new Vue({
el: '#app',
data: {
type: 'D',
}
})
script>
因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 元素。
<div id="app">
<template v-if="type">
<h1>Trueh1>
<p>输入内容p>
<input type="text">
template>
<template v-else>
<h1>Falseh1>
<p>输入内容p>
<input type="text">
template>
div>
<script>
var app = new Vue({
el: '#app',
data: {
type: true,
},
})
script>
该指令进行遍历,支持遍历的有:数字、字符串、数组、对象
第一个循环出来的是键值
<div id="app">
<ul>
<li v-for="(value, key, index) in obj1">
索引:{{ index }}---键值:{{ key }}---键名:{{ value }}
li>
ul>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
obj1: {'name': 'XWenXiang', 'age': 18}
},
})
script>
<div id="app">
<ul>
<li v-for="n in 10">
{{ n }}
li>
ul>
div>
<script>
new Vue({
el: '#app'
})
script>
<div id="app">
<ul>
<li v-for="(n, index) in array1">
{{index}}, {{ n }}
li>
ul>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
array1: ['a', 'b', 'c']
},
})
script>
<div id="app">
<ul>
<li v-for="n in str1">
{{ n }}
li>
ul>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
str1: 'XWenXiang'
},
})
script>
vue中使用的是虚拟DOM
,会和原生的DOM进行比较,然后进行数据的更新,提高数据的刷新速度(虚拟DOM用了diff算法)
设置的方式:key="变量"
1. 如果不使用 key 属性,组件默认都是就地复用;
2. 如果使用 key 属性并且绑定为索引值,效果和不使用 key 属性一样;
3. 如果使用了 key 属性并且绑定为非索引值的其他值,则会根据这唯一的 key 跟踪每个节点的身份从而
重用和重新排序现有元素。如果没有查找到,则会创建添加新的节点。
v-on
指令监听 DOM 事件,其中 click
点击事件使用较为频繁,还有 dblclick、keyup、 mousemove 等等
<a v-on:click="doSomething">...a>
<a @click="doSomething">...a>
<a @[event]="doSomething"> ... a>
v-on 还需要接收一个需要调用的方法名称。 在 methods
对象中定义方法 函数名字: function () {}
<div id="app">
<template v-if="type">
<h1>Trueh1>
<p>输入内容p>
<input type="text">
template>
<template v-else>
<h1>Falseh1>
<p>输入内容p>
<input type="text">
template>
<p><input type="button" @click="func" value="点击切换">p>
div>
<script>
var app = new Vue({
el: '#app',
data: {
type: true,
},
methods: {
func: function () {
this.type = !this.type
}
}
})
script>
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
button>
// ...
methods: {
warn: function (message, event) {
// 现在我们可以访问原生事件对象
if (event) {
event.preventDefault()
}
alert(message)
}
}
event: PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
事件 | 说明 |
---|---|
@click.stop | 当div事件和按钮事件同时弹出时,可用.stop阻止div事件弹出 |
@click.prevent | 当按钮submit提交时,加上.prevent可以阻止其自动提交 |
@keyup | 监听键盘抬起事件,当指定那个按键时,可以加上.enter就可以监听enter(回车键),以此类推 |
@click.native | 组件事件,加上.native后才可以监听自定义组件 |
@click.once | 加上.once后,只能发生一次事件,再点击不会生效 |
事件修饰符 | 释义 |
:-
.stop |只处理自己的事件,父控件冒泡的事件不处理(阻止事件冒泡)
.self |只监听触发该元素的事件,子控件冒泡的事件不处理
.prevent| 阻止a链接的跳转
.once |事件只会触发一次(适用于抽奖页面)
.capture |阻止捕获
.left |左键事件
.right | 右键事件
.middle | 中间滚轮事件
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生
用 v-on:click.prevent.self 会阻止所有的点击
而 v-on:click.self.prevent 只会阻止对元素自身的点击
事件 |
---|
.enter |
.tab |
.delete (捕获 “删除” 和 “退格” 键) |
.esc |
.space |
.up |
.down |
.left |
.right |
.ctrl |
.alt |
.shift |
.meta |
示例
<div id="app">
普通使用:<input type="text" v-model="myText" @keydown="func($event)">{{myText}}
<br><br>
监控enter键:<input type="text" v-model="myText1" @keydown.enter="func1()">{{myText1}}
div>
<script>
var vm = new Vue({
el: '#app',
data: {
myText: '',
myText1: '',
},
methods: {
func(event) {
console.log(event)
},
func1() {
console.log('enter 按钮被按下')
}
}
})
script>
从 event 可以得出键码值'KeyCode',除了使用修饰符提供的常见键盘按键,也可以直接使用键码,如下
<input type="text" v-model="myText" @keydown.49="func($event)">{{myText}}
v-model其实是一个语法糖,他背后的本质上是包含两个操作
v-model的作用为将程序员设定的变量与用户信息绑定,但用户信息不一定与value值绑定
方法 | 说明 |
---|---|
lazy | 等待input框的数据绑定失去焦点之后再变化 |
number | 数字开头,只保留数字,后面的字母不保留;字母开头,都保留 |
trim | 去除首尾的空格 |
<div id="app">
lazy的使用:<input type="text" v-model.lazy="myText">--->{{myText}}
<hr>
number的使用:<input type="text" v-model.number="myText2">--->{{myText2}}
<hr>
trim的使用:<input type="text" v-model.trim="myText3">--->{{myText3}}
div>
<script>
new Vue({
el: '#app',
data: {
myText: '',
myText2: '',
myText3: '',
},
})
script>
input 事件 | 释义 |
---|---|
input | 当输入框进行输入的时候,触发的事件 |
change | 当元素的值发生改变时,触发的事件 |
blur | 当输入框失去焦点的时候,触发的事件 |
change 和 blur 最本质的区别:
如果输入框为空,失去焦点后,change不会触发,但是blur会触发
filter() 方法
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
语法
array.filter(function(currentValue,index,arr), thisValue)
函数返回的是 true 则保留数据,返回的是 false 不保留数据
<div id="app">
<p><input type="text" @input="func" v-model="t">p>
<p v-for="n in new_list">{{n}}p>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
t: '',
old_list: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf'],
new_list: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf']
},
methods: {
func() {
// this.new_list = this.old_list.filter(function (item) {
// if (item.indexOf(vm.t) >= 0) {
// return true
// } else {
// return false
// }
// })
this.new_list = this.old_list.filter((item) => {
return item.indexOf(vm.t) >= 0
})
},
}
})
script>
上面的代码在函数中使用 this.t 是取不到
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是 attribute,所以我们可以用 v-bind
处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
使用变量动态的替换属性: v-bind:属性名='属性值'
v-bind 可以动态设置 style、class、url 等等属性
<div id="app">
<img :src='url' alt="" width="200px" height="200px">
<input type="button" @click="func">
div>
<script>
var app = new Vue({
el: '#app',
data: {
url: "https://img1.baidu.com/it/u=2502544893,756826411&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1656522000&t=16794d0de75ea3513f6b25460283c565",
urls: [
"https://img1.baidu.com/it/u=2502544893,756826411&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1656522000&t=16794d0de75ea3513f6b25460283c565",
"https://img1.baidu.com/it/u=3213474226,830910096&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1656522000&t=8af3292c53c392baafc4531d8f6f43f9",
"https://img2.baidu.com/it/u=85928140,4007661611&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1656522000&t=931b4d94f2551471be9b14653f47c3ad",
"https://img2.baidu.com/it/u=3524128265,2342452618&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1656522000&t=ae602d2151e5c9afc1a6197b672e3187"
],
},
methods: {
func: function () {
i = Math.floor((Math.random() * this.urls.length) + 0);
this.url = this.urls[i]
},
}
})
script>
class_str: 'yellow-back size-100',
class_array: ['yellow-back',],
class_obj: {'pink-back': true, 'size-40': false},
style_str:'font-size: 60px;background-color: aqua'
style_array: [{'font-size': '90px'}, {backgroundColor: 'aqua'}]
style_obj: {'font-size': '90px', backgroundColor: 'aqua'}
复选框的选中用 true 和 false 表示
<div id="app" style="margin: 0 auto; width: 200px;">
<p>复选框: <input type="checkbox" v-model="check"> {{check}}p>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
check: false,
},
})
多个复选框的 value 值在被选中后会添加到 v-model 中
<div id="app" style="margin: 0 auto; width: 200px;">
<p>篮球: <input type="checkbox" v-model="check" value="1">p>
<p>足球: <input type="checkbox" v-model="check" value="2">p>
<p>气球: <input type="checkbox" v-model="check" value="3">p>
{{check}}
<p>{{radio}}p>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
check: [],
},
})
script>
v-model 对应的值是单选框的 value
<div id="app" style="margin: 0 auto; width: 200px;">
<p>男: <input type="radio" v-model="radio" value="1">p>
<p>女: <input type="radio" v-model="radio" value="2">p>
<p>未知: <input type="radio" v-model="radio" value="3">p>
<p>{{radio}}p>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
radio: false,
},
})
script>
<div class="container">
<div class="row" id="app">
<table class="table table-striped">
<tr>
<th>商品名th>
<th>商品价格th>
<th>商品数量th>
<th>全选 <input type="checkbox" v-model="checkAll" @change="func2"> {{checkAll}}th>
<th>单价th>
tr>
<tr v-for="a in array1">
<td>{{a.name}}td>
<td>{{a.price}}td>
<td>
<button @click="a.number ++"> +button>
{{a.number}}
<button @click="a.number>1 ? a.number--:1"> -button>
td>
<td><input type="checkbox" v-model="goods" :value="a" @change="func">td>
<td>{{a.price * a.number}}td>
tr>
table>
<h3>已选择商品: {{goods}}h3>
<h2 class="pull-right">总价: {{func1()}}h2>
div>
div>
<script>
var vm = new Vue({
el: '#app',
data: {
array1: [
{name: 'A', price: 23, number: 2},
{name: 'B', price: 13, number: 1},
{name: 'C', price: 42, number: 5},
{name: 'D', price: 648, number: 3},
],
goods: [],
checkAll: false,
},
methods: {
func() {
this.checkAll = (this.array1.length == this.goods.length)
},
func1() {
var all = 0
this.goods.forEach((v, k) => {
all += v.price * v.number
})
return all
},
func2() {
this.goods = this.checkAll ? this.array1 : []
},
},
})
script>
body>
array.forEach(function(currentValue, index, arr), thisValue)
for (i = 0; i < this.xxx.length; i++){}
for (i in this.array1){}
for (item of this.array1) {}
在计算属性 computed
中编写的函数都可以像属性一样调用,作用和 methods
一样,它们之间的区别是 computed 是基于它的依赖缓存,只有依赖的关系改变的时候才会执行。而 methods ,在重新渲染的时候,函数都重新调用执行 (直接加括号调用的函数),可以看下面的例子理解。
<div id="app" style="text-align: center">
<p>name: <input type="text" v-model="name">---> {{methodsFunc()}}</p>
<p>pwd: <input type="text" v-model="pwd">---> {{pwd}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
pwd: '',
},
methods: {
methodsFunc() {
console.log('methodsFunc 函数被执行')
return this.name.substr(0, 1).toUpperCase() + this.name.substr(1,)
}
},
})
</script>
<div id="app" style="text-align: center">
<p>name: <input type="text" v-model="name">---> {{computedFunc}}</p>
<p>pwd: <input type="text" v-model="pwd">---> {{pwd}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
pwd: '',
},
computed : {
computedFunc() {
console.log('computedFunc 函数被执行')
return this.name.substr(0, 1).toUpperCase() + this.name.substr(1,)
}
}
})
</script>
<div id="app" style="margin-left: 200px;">
<p><input type="text" v-model="t"></p>
<p v-for="n in new_list">{{n}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
t: '',
old_list: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf']
},
computed: {
new_list() {
return this.old_list.filter(item => {
return item.indexOf(this.t) >= 0
})
},
}
})
</script>
我们可以通过 watch
来响应数据的变化。在 watch对象中写函数,并且函数名就是 data 中的变量名,只要这个变量发生变化,就会触发该函数的执行。函数可以获取一个参数,用于表示输入的值,下面代码用 val 表示
<div id="app">
<input type="text" v-model="func">
</div>
<script>
var vum = new Vue({
el: '#app',
data: {
func: '',
},
watch: {
func(val){
console.log('watch 执行', val)
}
},
})
</script>
<div id="app">
<input type="text" v-model="func">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
func: '',
},
})
vm.$watch('func', (val)=> console.log('watch 执行', val) )
</script>
<div id="app">
<p>克: <input type="text" v-model="func"></p>
<p>斤: <input type="text" v-model="func1"></p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
func: '',
func1: '',
},
watch: {
func(val) {
this.func1 = val * 0.002
},
func1(val) {
this.func = val * 500
},
},
})
</script>