Vue 是一个渐进式框架,何为渐进式
Vue的特点和Web开发中常见的高级功能
解耦视图和数据
可复用的组件
前端路由技术
状态管理
虚拟DOM
Vue是声明式编程
MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。
Model(模型):表示应用程序核心(如数据库)
View(视图):视图代表模型包含的数据的可视化
Controller(控制器):控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开
MVC是多种设计模式的组合,组成MVC的三个模式分别是组合模式、观察者模式、策咯模式,MVC在软件开发中发挥的威力,最终离不开这三个模式的默契配合。
组合模式:组合模式只在视图层活动,组合模式的类层次结构是树状的,例子:而我们做Web时视图层是html页面,html的结构就是树状的。
观察者模式:观察者模式有两部分组成,被观察的对象和观察者,观察者也被称为监听者。对应到MVC中,Model是被观察的对象,View是观察者,Model层一旦发生变化,View层即被通知更新。
策略模式:策略模式是View和Controller之间的关系,Controller是View的一个策略,Controller对于View是可替换的。
MVC各层之间关系所对应的设计模式:
View层:单独实现了组合模式
Model层和View层:实现了观察者模式
View层和Controller层:实现了策咯模式
Model-View-Presenter ;MVP 是从经典的模式MVC演变而来
MVP与MVC有着一个重大的区别:在MVP中View并不直接访问Model,它们之间的通信是通过Presenter 来进行的,所有的交互都发生在Presenter内部,Presenter 完全把 view 和 model 进行了分离,Presenter 与具体的 view 是没有直接关联的,而是通过定义好的接口进行交互,从而在变更view时可以保证Presenter 不变
Vue.js 就是MVVM的代表框架。
View 的变化会自动更新到 viewModel,viewModel 的变化也会自动同步到view上显示。
(ViewModel)视图模型是暴露公共属性和命令的视图的抽象。MVVM没有MVC模式的控制器,也没有MVP模式的presenter,有的是一个绑定器。在视图模型中,绑定器在视图和数据绑定器之间进行通信。其作用:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现,我们称之为数据的双向绑定。
Mustache 语法中可以直接写变量,也可以写简单的表达式:
<div id="app">
<h2>Message:{
{message}}h2>
<h2>{
{firstName + '' + lastName}}h2>
<h2>{
{firstName}} {
{lastName}}h2>
div>
vue 允许在表达式后面添加过滤器,多个过滤器可以串联
{
{example | filterA | filterB}}
注意:
v-bind
有时只需渲染一次数据,可以通过“*”实现:
<span>text: {
{*msg}}span>
若为HTML片段:
<div>logo: {
{
{logo}}}div>
logo:'<<span>hhhspan>>'
<span v-once>这个将不会改变: {
{ msg }}span>
注意:
背景:某些情况下,从服务器请求的数据本身就是HTML,如果通过{ {}} 输出,输出的是HTML源代码,不会对其进行解析
<h2 v-html='link'>h2>
// link :'<a> href = 'http://www.baidu.com'a>'
<h2 v-text='message'>h2>
<p>{
{message}}p> //hello world!
<p v-pre>{
{message}}p> //{
{message}}
当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会直接显示出未编译得Vue 源代码
<div id="app" v-cloak>
{
{context}}
div>
<script>
var app = new Vue({
el: '#app',
data: {
context:'互联网头部玩家钟爱的健身项目'
}
});
script>
[v-cloak]{
display: none;
}
<div id="app">
<a v-bind:href="">hhha>
<img v-bind:src="" alt="">
div>
<script>
let app = new Vue({
el:"#app",
data: {
logoURL:'https://vuejs.org/images/logo.png',
link:'https://vuejs.org'
}
})
script>
用法一:直接通过{}绑定一个类
<h2 :class="{
'active': isActive}">Hello Worldh2>
用法二:通过判断,传入多个值
<h2 :class="{
'active': isActive, 'line': isLine}">Hello Worldh2>
用法三:和普通的类同时存在,并不冲突
<h2 class="title" :class="{
'active': isActive, 'line': isLine}">Hello Worldh2>
用法四:若过于复杂,可以放在一个methods或computed中
注意:classes是计算属性
<h2 class="title" :class="classes">h2>
数组语法(用的少)
:class后跟的是一个数组
用法一:直接通过{}绑定一个类
<h2 :class="['active']}">Hello Worldh2>
用法二:通过判断,传入多个值
<h2 :class="['active','line']">Hello Worldh2>
用法三:和普通的类同时存在,并不冲突
<h2 class="title" :class="['active','line']">Hello Worldh2>
用法四:若过于复杂,可以放在一个methods或computed中
注意:classes是计算属性
<h2 class="title" :class="classes">h2>
用 v-bind:style 来绑定一些内联样式
写属性名时注意,如font-size:
绑定的方法:
语法:
:style ="{color:currentColor, fontSize:fontSize + "px"}"
style后跟的是一个对象类型:
<h2 :style="{fontSize:'50px'}">Hello Worldh2>
注意:上面的50px一定要加单引号,不加单引号会被认为是变量,而变量名不能以数字开头就会报错,加了单引号是字符串,vue解析时会去掉单引号
:style="[baseStyles,overrideingStyles]"
style后面跟的是一个数组类型
<div id="app">
<h2>总价格:{
{totalPrice}}h2>
div>
<script src="./vue.js">script>
<script>
let app = new Vue({
el:"#app",
data: {
books:[
{
id: 110, name: 'hhh', price: 119},
{
id: 111, name: 'xxx', price: 105},
{
id: 112, name: 'sss', price: 98},
{
id: 113, name: 'jjj', price: 87}
]
},
computed: {
totalPrice: function() {
let res = 0;
for(let i=0; i < this.books.length; i++) {
res += this.books[i].price;
}
return res;
//其他的for写法
for(let i in this.books){
this.books[i];
}
for(let book of this.books){
}
}
}
})
script>
注意:totalPrice 不加括号,把它当成属性来看待
计算属性一般是没有set方法的,为只读属性
<div id="app">
<h2>{
{firstName}} {
{lastName}}h2>
<h2>{
{getFullName()}}h2>
<h2>{
{fullName}}h2>
div>
要点:computed 属性有缓存的 ,不管需要调用多少个{ {fullName}},都只计算一次
需求:用户再次登录时,可以切换使用用户账号登录或邮箱地址登录
<div id="app">
<span v-if="type === 'username'">
<label for="">用户账号:label>
<input placeholder="用户账号">
span>
<span v-else>
<label for="">邮箱地址:label>
<input placeholder="邮箱地址">
span>
<button @click="handleToggle">切换类型button>
div>
<script>
let app = new Vue({
el:"#app",
data: {
type:'username'
},
methods: {
handleToggle() {
this.type = this.type === 'email' ? 'email' : 'username';
}
}
})
script>
<span v-if="isUser">
<label for="username">用户账号:label>
<input type='text' id='username' placeholder="用户账号" key='username'>
span>
<span v-else>
<label for="">邮箱地址:label>
<input type='text' id='email' placeholder="邮箱地址" key='email'>
span>
<button @click="isUser = !isUser">切换类型button>
要点:添加了不同 key 的 input 就不会出现重复利用的情况
也用于决定一个元素是否渲染
遍历数组:
<ul>
<li v-for="item in names">{
{item}}li>
ul>
// 遍历过程中获取索引值
<ul>
<li v-for="(item, index) in names">
{
{index+1}}.{
{item}}
li>
ul>
<ul>
<li v-for="item in names">
{
{$index}}-{
{item}}
li>
ul>
遍历对象:
<ul>
<li v-for="(value,key) in info">{
{value}}-{
{key}}li>
ul>
<ul>
<li v-for="(value,key,index) in info">{
{value}}-{
{key}}-{
{index}}li>
ul>
要点:
- {
{value}}-{
{key}}
官方推荐在使用 v-for 时,给对应的元素或组件添加上一个key属性,给每个节点做唯一的标识,作用:
//注意:通过索引值修改数组中的元素
this.letters[0] = 'hhhh'; // 非响应式
this.letters.splice(0, 1, 'hhhh'); //响应式
Vue.set(this.letters,0,'hhhh'); //响应式
高阶函数:filter/reduce/map
要点:
1、filter中的回调函数必须返回布尔值,当返回true时,函数内部会自动将这次回调的值n加入到新的数组中;当但会false时,函数内部会过滤此次的值n
2、回调函数执行的次数为数组元素的个数
3、新数组自动生成,只需要一个变量去接收
const nums = [10,20,304,304,1204,221,45];
let newNums = nums.filter(function(n) {
return n < 100;
})
console.log(newNums);
let newNums2 = nums.map(function(n) {
return n * 2;
})
对数组中所有内容进行汇总:全部相加或者全部相乘
let total = nums.filter(n => n < 100).map(n => n*2).reduce((pre,n) => pre + n);
<div id="app">
<h2>点击次数:{
{counter}}h2>
<button v-on:click="counter++">按钮1button>
<button @click="btnClick">按钮2button>
div>
<script>
let app = new Vue({
el:"#app",
data: {
counter:0
},
methods: {
btnClick() {
this.counter++
}
}
})
script>
当通过methods中定义方法,以供@click调用,需要注意参数问题:
情况一:若该方法不需要额外参数,那方法后的()可以不添加,若方法中本身由一个参数,那么会默认将原生事件event参数传递进去
情况二:若需要同时传入某个参数,同时需要event时,可以通过$event传入事件
<div id="app">
<h2>点击次数:{
{counter}}h2>
<button @click="handleAdd">button>
<button @click="handleAddTen(10,$event)">button>
div>
<script>
let app = new Vue({
el:"#app",
data: {
counter:0
},
methods: {
handleAdd(event) {
this.counter++;
},
handleAddTen(count,event) {
this.counter += 10;
}
}
})
script>
Vue提供修饰符来帮助我们处理一些事件:
<button @click.stop="btnClick">button>
<button @click.prevent="doThis">button>
<form @click.prevent>form>
<button @click.stop.prevent="doThis">button>
<input @keyup.enter="onEnter">
<input @keyup.13="onEnter">
<button @click.once="doThis">button>
作用:实现表单元素和数据的双向绑定
v-model实际是语法糖,其背后是包含两个操作:
<div id="app">
<input type="text" v-model="message">
<h2>{
{message}}h2>
div>
<script>
let app = new Vue({
el:"#app",
data: {
message:''
}
})
script>
当我们在输入框中输入内容时,因为input中v-model绑定了message,所以会实时将输入的内容传递给message,message发生变化。而又使用了Mustache语法将message的值绑定到DOM中,所以DOM会发生相应的变化
要点:如果v-model 都绑定的是同一个变量,那么删除name后也可以互斥
<div id="app">
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
label>
<h2>您的选择是:{
{isAgree}}h2>
<button :disaled="!isAgree">下一步button>
div>
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<input type="checkbox" value="足球" v-model="hobbies">足球
<input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
<input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
<h2>您的爱好是:{
{hobbies}}h2>
<script>
let app = new Vue({
el:"#app",
data: {
message: '你好啊',
isAgree: false, //单选框
hobbies: [] //多选框
}
})
script>
要点:value是点击后会返回的值
单选
多选
<div id="app">
<select name="abc" v-model="fruit">
<option value="苹果">苹果option>
<option value="香蕉">香蕉option>
<option value="西瓜">西瓜option>
<option value="梨子">梨子option>
select>
<h2>您选择的水果是:{
{fruit}}h2>
<select name="abc" v-model="fruits" multiple>
<option value="苹果">苹果option>
<option value="香蕉">香蕉option>
<option value="西瓜">西瓜option>
<option value="梨子">梨子option>
select>
<h2>您选择的水果是:{
{fruits}}h2>
div>
<script>
let app = new Vue({
el:"#app",
data: {
message: '你好啊',
fruit:'香蕉',
fruits:[]
}
})
script>
<div id="app">
<label v-for="item in originHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="hobbies">{
{item}}
label>
div>
<script>
let app = new Vue({
el:"#app",
data: {
message: '你好啊',
hobbies:[],
originHobbies:['篮球','足球','乒乓球','羽毛球','台球']
}
})
script>
lazy 修饰符
number 修饰符
作用:可以让输入框中输入的内容自动转换为数字类型
默认情况下,在输入框中无论我们输入的事数字还是字母,都会被当作字符串类型进行处理。当若我们希望处理的事数字类型,最好直接将内容当作数字处理
trim 修饰符
<input type="text" v-model.lazy="message">
<h2>{
{message}}h2>
<input type="number" v-model.number="age">
<h2>{
{age}}h2>
ES6中,对对象字面量进行了很多增强。
// ES6之前
let name = 'why';
let age = 18;
let obj1 = {
name: name,
age: age
}
console.log(obj1);
// ES6之后
let obj2 = {
name, age
}
console.log(obj2);
// ES6之前
let obj1 = {
test: funtion() {
console.log("obj1");
}
};
obj1.test();
// ES6之后
let obj1 = {
test() {
console.log("obj2");
}
};
obj2.test();
vue 每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建(new)、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
beforeCreate()
此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据。
create()
实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。可以调用methods中的方法,改变data中的数据;获取computed中的计算属性,且常在该钩子里进行网络请求
beforeMount()
在挂载开始之前被调用:相关的 render 函数首次被调用(虚拟DOM)。实例已完成以下的配置: 编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂载html到页面上。
mounted()
挂载完成,也就是模板中的HTML渲染到HTML页面中, 此时一般可以做一些ajax操作,mounted只会执行一次
beforeUpdate()
在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前,可以在该钩子中进一步地更改状态,不会触发附加地重渲染过程
update()
在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用,调用时**,组件DOM已经更新,所以可以执行依赖于DOM的操作**,在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,该钩子在服务器端渲染期间不被调用
beforeDestroy()
在实例销毁之前调用,实例仍然完全可用
destroyed()
在实例销毁之后调用,调用后,所有的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用