了解几个概念
SPA:
single page application 单页面应用
优点:加载快,用户体验好 缺点:不利于SEO,首屏加载时间长 a页面—>index.html/#/a b页面—>index.html/#/b
MPA:(多用pc端)
多页面应用
优点:有利于SEO优化 缺点:会有白屏,用户体验不好 a页面—>a.html b页面—>b.html
MVVM设计模式
M-model模型:用来处理数据, V-view视图:展示数据, VM-viewModel 视图模型 模型(model)通过了视图模型 决定了视图(view) 视图(view) 通过视图模型 修改模型 (model) 视图模型是模型和视图之间的桥梁。
MVC设计模式
M-model模型:用来操作数据库并处理处理数据, V-view视图:展示数据, C-contriller控制器:用来接受请求,调用模型层将数据分配给视图层,然后将视图层的渲染回复给浏览器
vue基础
1.vue的介绍
官网:Vue.js
介绍:
vue是渐进式 JavaScript 框架 ,
渐进式 :我们可以只使用vue的基础版,也可以使用脚手架,也可以和vue-router和vuex一起使用 。
框架:不需要知道这个框架是怎么写的,知道怎么用的就行.
特点
1.采用组件化开发,提高代码的复用率,让代码更好维护。
2.数据驱动,让编码人员无需直接操作dom,只要操作数据页面就会重新渲染,提高开发效率
3.使用虚拟dom+diff算法,尽可能的复用dom节点,提高了渲染效率
虚拟dom Vs 真实dom
真实dom
在浏览器上展示的dom元素
虚拟dom
虚拟dom就是一个js对象
//vue中的模版 <div title='hello' name="zhangsan" @click="_add()"> <span>我是span1</span> <span>我是span2</span> </div>
vue中的虚拟dom { el:'div', attr: { title:"hello", name:'zhangsan' } }, event:{ onclick:function(){ } }, children:[{ el:'span', attr:{}, children:"我是span" },{ el:'span', attr:{}, children:"我是span" }] }
对比
jquery库:就是直接操作的是真实的dom,vue操作的是虚拟dom
需求:需要把1000条数据展示在网页中,
使用真实dom,我们需要操作1000个dom元素,但是当在数据后添加一条数据成1001条数据时,我们又要操作1001个dom
使用虚拟dom,开始我们需要生成1000个虚拟dom,然后将虚拟dom转成1000个真实dom,这时在数据后添加一条数据成1001条数据时,我们会重新生成1001个虚拟dom,然后拿新生成的1001个虚拟dom和旧的1000个虚拟dom通过diff算法比对,这时只需要新建一个真实的dom就行了,
从上面就能看出来,这样提高了dom渲染效率
优缺点
优点
-
1.轻量级的数据框架,100kb
-
2.双向数据绑定 ,数据驱动
-
3.提供了指令
-
4.组件化开发
-
5.客户端路由
-
6.状态管理
缺点
-
1.Vue 底层基于 Object.defineProperty 实现响应式,而这个 api 本身不支持 IE8 及以下浏览器,所以Vue不支持IE8及其以下浏览器;
-
2.使用Vue脚手架 打造的是SPA,所以不利于搜索引擎优化(SEO);
-
3.由于 CSR (client side render)的先天不足,导致首屏加载时间长,有可能会出现闪屏。
2vue的初体验
安装vue
下载
可以下载到本地使用script标签引入,开发时我们可以使用开发版本,上线可以使用生产环境的
cdn
可以使用script标签引入vue的cnd的链接
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
npm
npm install vue@2.* <script src="./node_modules/vue/dist/vue.js"></script>
vue-cli脚手架
这个我们如果需要开发一个大的项目可以选择这个
安装vue-devtool
在谷歌的插架市场上安装vue的调试工具,国内没有办法访问谷歌的插件市场,需要翻墙
在火狐插架市场上安装vue-devtool
第一个vue的代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> 我的名字是:{ {name}}我的年龄是:{ {age}} <button @click="_add">age+1</button> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> <script> let vm=new Vue({ el:"#app", data:{ name:"hello", age:18 }, methods:{ _add:function(){ this.age=this.age+1 } } }) </script> </html>
3分析第一个vue代码
引入了vue后,就有一个Vue的类,我们可以使用new Vue创建一个vue的实例,new一个vue实例时需要传递一个对象参数,参数如下
el:
功能:设置vue实例的挂载点,
类型:string | Element
限制:只在用 new
创建实例时生效。一个vue实例只能设置一个挂载点,如果有多个挂载点,第一个生效
详细:
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。
在实例挂载之后,元素可以用 vm.$el
访问。
let vm=new Vue({ el:document.getElementById("app")//可以是个对象 }) console.log($el) //能获取到$el的挂载点
如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用 vm.$mount()
手动开启编译。
总结:
设置vue实例的挂载的元素,也可以使用vm.$mount("#app")设置挂载点,使用el选项的优先级高于$mount
let vm=new Vue({ data:{ name:"hello", age:18 }, methods:{ _add:function(){ this.age=this.age+1 } } }) vm.$mount("#app") vm.$mount(document.getElementById("app"))
data:
功能:设置vue实例或者组件实例的初始化数据,这里的数据是就具有响应式的
类型:Object | Function
限制:组件的定义只接受 function
。
总结:
-
data可以是一个对象,也可以是一个函数返回值必须是一个对象,但是如果该vue实例是一个组件实例,那么data必须是一个函数;
-
data对象的原型的属性不具有响应式的,data对象上只能有属性,不推荐有方法(有了也不报错,没有意义不具有响应式)data对象上属性的可以是一个对象
-
data中的属性不能以_和$开头,(会报警告,不会在页面展示也具有响应式)
-
可以通过
vm.$data
访问原始数据对象,访问vm.name
就相当于访问vm.$data.name
-
可以通过实例对象添加一个属性
vm.money=100
,但是添加的属性不具有响应式,如果想让添加的属性具有响应式可以使用vm.$set()
添加属性
let vm=new Vue({ el:document.getElementById("app"), data(){ return { name:"hello", age:18 } } })
methods:
功能:给vue实例设置函数
类型:{ [key: string]: Function }
,是一个对象,对象中只有方法
限制:对象中的方法不能是箭头函数,如果用箭头函数箭头函数中的this就不是vue实例了,是undefined
详细:
methods 中的方法被添加到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this
自动绑定为 Vue 实例。
template:
功能:给vue实例设置template模版,给vue实例设置渲染内容
类型:string
说明:如果参数中有这个选项,模版字符串的优先级高于挂载点元素的内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app">我是app的内容,我的名字是:{ {name}}我的年龄是:{ {age}}<button @click="_add">age+1</button></div> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> <script> let vm=new Vue({ el:document.getElementById("app"), data(){ return { name:"hello", age:18 } }, template:`<div>我是template的内容--{ {name}}---{ {age}}<button @click="_add">age+1</button></div>`, methods:{ _add:function(){ this.age=this.age+1 } } }) </script> </html>
详细:可以是一个模版字符串,如果以#开头他就是一个模版的引用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app">我是app的内容,我的名字是:{ {name}}我的年龄是:{ {age}}<button @click="_add">age+1</button></div> <template id="content"> <div> 我是templates的内容--{ {name}}---{ {age}} <button @click="_add">age+1</button> </div> </template> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> <script> let vm=new Vue({ el:document.getElementById("app"), data(){ return { name:"hello", age:18 } }, template:`#content`, methods:{ _add:function(){ this.age=this.age+1 } } }) </script> </html>
render: (不重要了解即可)
功能:渲染一个虚拟dom
类型:(createElement: () => VNode) => VNode
说明:如果参数中有这个选项,这个选项的优先级高于模版字符串
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app">我是app的内容,我的名字是:{ {name}}我的年龄是:{ {age}}<button @click="_add">age+1</button></div> <template id="content"> <div> 我是templates的内容--{ {name}}---{ {age}} <button @click="_add">age+1</button> </div> </template> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> <script> let vm=new Vue({ el:document.getElementById("app"), data(){ return { name:"hello", age:18 } }, template:`#content`, render:function(h){ let vnode=h('div',{title:"hello"},`我是内容--${this.name}---${this.age}`) console.log(vnode) return vnode }, methods:{ _add:function(){ this.age=this.age+1 } } }) </script> </html>
renderError:
自己看文档吧
4.模版语法
了解:我们在上面的实例中在模版中写的不是html
,而是vue的模版字符串,在vue运行时,vue会先把模版字符成按照算法(栈指针)解析成虚拟dom(就是一个对象),然后在使用js原生的dom操作将虚拟dom转化成真实的dom(真正的html)放到挂载点中,我们就能看到页面了,当数据发生变化了会重新生成一个新的虚拟dom,然后新的虚拟dom和之前老的虚拟dom进行diff算法比对,计算出一个补丁,我们只需要重新渲染补丁就能把页面更新了
注意:模板字符串一定要用一个根元素包裹,否则报错
内容
<div> 我是{ {name}}---{ {user.age}} </div>
name 和user.name值发生变化,模板会重新渲染
<span v-once>这个将不会改变: { { name }}</span>
使用v-once指令可以让这个值不改变,插值处的内容不会更新
<template id="content"> <div> 我是{ {name}}---{ {desc}}---<span v-html="desc"></span> </div> </template> let vm=new Vue({ el:document.getElementById("app"), data(){ return { name:"hello", age:18, desc:"<h1>我是一个介绍</h1>" } }, template:"#content" })
vue为了防止xss攻击默认不会解析变量中的html元素,把是否解析的选择交到开发者的手中,如果想让他发生解析可以使用v-html
属性
v-bind
如果属性是一个变量我们需要使用v-bind:指定绑定属性,v-bind可以省略
<div v-bind:title="msg">hello</div> //变量被解析了 <div :title="msg"></div>
不用v-bind绑定的属性不会发生解析
<div title="msg">hello</div> //title的属性就是msg字符串
v-model
<input type="text" :value="name" />
以上能看到name的值,但上面的绑定是单向的数据绑定,就是我们改变了输入框的值name的值并没有发生变化
我们可以使用v-model实现双向书绑定,即数据变,输入框变;输入框变数据也发生变化
<input type="text" v-model:value="name" />
<input type="text" v-model="name" /> //简写
v-model不能使用在非表单元素上
<span v-model:title="msg">我是内容</span> //报错
表达式
能赋值给一个变量的东西就是表达式
属性和内容除了是变量之外还可以是表达式,
<div>{ {1+1}}---{ {age+1}}----{ {name.substring(0,5)}}</div> <div :title="age>18?'hello':'world'"></div> <input type="checkbox" checked="false"> //这样写checked的属性是false字符串, <input type="checkbox" :checked="false"> //这样写checked就是布尔类型的false <div :title="msg">hello</div> //msg是一个变量 <div :title="'msg'">hello</div> //msg就是一个字符串
值也是表达式,变量也是表达式
class的绑定
字符串
<div class="basic" :class="color"> 我是{ {name}} </div> data(){ return { name:"hello", age:18, color:"red" } }
结果:class=“basic red”,静态的class属性会和绑定的class属性会合并,只能有一个绑定的class,下面的第二个:class
不会生效
<div class="basic" :class="color" :class="age>16?'hello':'world'"> 我是{ {name}} </div>
对象
如果我们有多个class需要用到表达式,可以使用对象
<div class="basic" :class="{color:age<16,active:true}"> 我是{ {name}} </div> data(){ return { name:"hello", age:18, color:"red" } }
结果:class="basic active"
,对象中属性名就是类名,属性值如果为真就有这个类为假就没有这个类,属性值可以是个表达式,也可以是:
<div class="basic" :class="customclass"> 我是{ {name}} </div> data(){ return { customclass:{ active:true, text:false } } }
数组
<div class="basic" v-bind:class="[activeClass, errorClass]"></div> data: { activeClass: 'active', errorClass: 'text-danger' }
结果:class="basic active,text-danger"
,可以是个数组,数组的每个值就是一个类名,数组中的值可以是表达式
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
数组值中可以是一个对象结构
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
class绑定在自定义组件上
当在一个自定义组件上使用 class
property 时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。
style样式绑定
如果绑定的是style,那么style不能是字符串
对象风格
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> data: { activeColor: 'red', fontSize: 30 }
数组风格
<div v-bind:style="[{ color: activeColor, fontSize: fontSize + 'px' },{backgroundColor:'green'}]"></div> data: { activeColor: 'red', fontSize: 30 }
:style绑定到自定义组件上,不能添加到该组件上,vue会给:style自动加上不同浏览器引擎的前缀
条件渲染
v-if
<h1 v-if="age>18">我成年了</h1> <h1 v-if="age>18">我成年了</h1> <h1 v-else>我未成年了</h1> <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> data(){ return { age:17 } }
template元素
如果判断的元素多可以使用templat