day01
1. 原生DOM vs 函数库 vs 框架
原生DOM: 优点: 跨平台好
缺点: 繁琐
函数库jQuery: 优点: 对原生DOM的每个API进行了简化
缺点: 并没有简化开发的步骤
框架Vue,AngularJS,React: 优点: 彻底简化了开发的步骤
缺点: 需要转变观念
2. 什么是Vue:
Vue是基于MVVM设计模式的渐进式的前端js框架
渐进式: 可以有选择的逐步使用框架中的组件
“全家桶”: 必须全盘使用所有组件
前端js框架: 不需要nodejs,仅靠浏览器就可独立运行
为什么后续需要nodejs?将Vue框架中浏览器不认识的新技术翻译为浏览器认识的ES5的对等标准——已经封装好了
何时: 侧重于以数据操作为主的前端项目开发
3. 如何使用Vue:
下载: cn.vuejs.org
最新稳定版: 2.6
开发版: 未压缩的,包含完备注释和错误提示信息
优: 可读性好
缺: 体积大,不便于传输
生产版: 代码经过压缩,删除了所有注释和错误提示信息
优: 体积最小化,便于传输
缺: 不便于学习和阅读
使用Vue 2种方式:
- 下载独立的vue.js,在网页中引入:
- 用脚手架代码:
原理: MVVM设计模式:
旧的前端代码划分:
html: 定义网页的内容
css: 定义网页的样式
js: 增删改查,事件绑定
MVVM设计模式将前端内容重新划分: (步骤)
- 界面(View): html+css
为HTML添加了动态功能: 变量,if else, for - 模型数据(Model): 所有页面上需要的/可能发生变化的数据。集中定义在data={ 数据1:值1, 数据2:值2, … }
往往模型数据都是ajax从服务端请求来的。 - 控制器(ViewModel):将视图View和模型数据(Model)绑定在一起。
绑定: 监控视图和模型,始终保持模型数据与页面自动同步
控制器ViewModel中包含两大子系统:- 响应系统: 监控模型中每个变量的变化
只要有变量发生变化,立刻发出通知!
本质: 将data中每个属性都提升为new Vue对象的访问器属性。只要修改new Vue对象的访问器属性,就可修改data中的变量。但是,同时会发出通知! - 虚拟DOM树:
什么是: Vue临时生成的仅保存可能变化的元素和属性的DOM树
何时生成: new Vue()边扫描受监控的页面元素,边创建虚拟DOM树,仅保留可能发生变化的元素
何时使用: 响应系统通知某个变量被改变时,告知虚拟DOM树。虚拟DOM树快速遍历自己,找到受影响的DOM元素,仅修改受影响的DOM元素
总结: 虚拟DOM树:- 内容少,遍历极快
- 仅修改受影响的DOM元素的属性或内容
- 响应系统: 监控模型中每个变量的变化
4. 绑定语法:
{{变量名}} Interpolation 插值
告知Vue框架,这里需要哪个变量
{{}}中还可写一切正确的有返回值的js表达式:
比如: 运算, 三目, 函数调用,访问数组元素,访问对象属性,模板字符串
问题: 只能绑定内容,不能绑定属性和事件等…
5. 指令directive
什么是: Vue新增的增强HTML功能的特殊属性
为什么: HTML缺少动态原因所需的要素: 运算, 分支,循环
包括:
- 专门绑定属性值的指令:
v-bind
何时: 绑定属性值
如何:<ANY v-bind:属性名="js表达式">
v-bind: 让普通的属性的""中也可以执行js程序
其实可省略: v-bind
所以: 今后只要绑定属性都用 :属性名="js表达式"
- 事件绑定:
v-on
如何:
HTML中: <ANY v-on:事件名="处理函数名">
<script>中
new Vue({
el:"#app",
data:{ 模型变量 },
methods:{
处理函数 (){
this.模型变量
}
}
})
其实: v-on: 可简写为@,
所以,今后绑定事件都用@事件名="处理函数"
- v-if: 为HTML添加分支结构
v-if 控制一个元素的显示隐藏
<ANY v-if=“条件表达式”
v-if v-else 可控制两个元素二选一显示
<ANY v-if=“条件表达式”
<ANY v-else
v-if v-else-if v-else 可控制多个元素多选一显示
<ANY v-if=“条件表达式”
<ANY v-else-if=“条件表达式”
<ANY v-else - v-show: 控制一个元素显示隐藏
用法同v-if: <ANY v-show=“条件表达式”
本质: 用display:none隐藏元素
v-if的本质: 用删除元素节点的方式,隐藏元素 - v-for: 根据数组反复生成多个相同结构的元素
用法:<ANY v-for="elem of 数组"> //elem可当做模型变量使用,用作绑定 </ANY>
of
会依次读取数组中每个元素
每读取一个元素就创建一个<ANY>
- 绑定html片段:
问题: {{}}无法绑定HTML片段,它会努力保持HTML片段原样显示
解决:v-text="变量"
不行,v-text等效于{{}}
v-html="变量"
可以,会被浏览器解析为正文
总结: 只要绑定的内容是HTML片段,都用v-html v-cloak
: 在vue加载完之前,短暂隐藏{{}}语法,不让用户看到
如何:- 在界面中想隐藏的元素/父元素上添加v-cloak自定义属性
- 在页面的
<style>
中用属性选择器找到所有有v-cloak
属性的元素,设置隐藏:
<style>[v-cloak]{ display:none }</style>
结果: 当vue对象加载完成,会自动查找所有v-cloak属性,自动移除。所有元素就重新显示出来
v-pre
: 保护内容中碰巧出现的{{}}不被VUE编译,保持原样显示v-once
: 控制一个变量只在开始时绑定一次,之后即使模型变量变化,也不再更新.
6. 双向绑定:
单向绑定: 将内存中模型数据中的值绑定到界面上(Model->View)
问题: 无法绑定表单元素的值
表单元素值的修改,无法自动映射到内存中
解决: 今后只要绑定表单元素,都用双向绑定
什么是双向绑定: 即能将Model中的数据绑定到界面上(Model->View),又能自动将界面上的修改,映射到内存中(View->Model)
如何: <表单元素 v-model:value="模型变量">
简写: 1. <input type="text" <textarea> <select>
都可简写为: v-model="模型变量"
省略:value,默认绑定value属性
2. <input type="checkbox">
可简写为: v-model=“模型变量”
但默认绑定的是checked
3. <input type="radio">
可简写为: v-model=“模型变量”
但用模型变量和radio的value做比较
如果模型变量的值=radio的value时,就选中
如果模型变量的值!=radio的value时,就不选中
day02
1. 双向绑定:
哪个属性会被改变,v-model就自动绑定哪个属性
- 文本框和文本域:
<input type="text" v-model[:value]="变量">
<textarea v-model[:value]="变量">
- 单选按钮:
<input type="radio" name="分组" value="1" v-model="sex">男
<input type="radio" name="分组" value="0" v-model="sex">女
v-model
先用sex的值和value做比较
哪个value==sex
,当前radio就选中,否则就不选中 - 复选框:
单独使用:
<input type="checkbox" v-model="isAgree">同意
v-mode:checked 且isAgree是bool类型
- select元素:
<select v-model="orderStatus"> value=30
<option value="10" >未付款</option>
<option value="20" >已付款</option>
<option value="30" >已发货</option>
<option value="40" selected >已签收</option>
watch
监控: 当某个模型变量被修改时,自动触发的函数
wath:{
受监控的变量名(){
//会在受监控的变量被双向绑定修改时自动执行
}
}
2. 绑定class和style
绑定style:
- 其实style也是一个普通的字符串属性,也可以:
<ANY :style="模型变量"
模型变量: “css属性:值; css属性:值; …”
问题: 字符串拼接很繁琐,不直观 - 将style看做一个对象绑定:
<ANY :style="对象名"
data:{ 对象:{ css属性:值, css属性:值 }
}//css属性都要去横线变驼峰!
绑定class
- 其实
class
属性也只是一个字符串属性,也可以:
<ANY :class="拼接字符串"
- 都用对象方式绑定:
<ANY :class="对象名"
//"success"
data:{
对象名:{
hide: false,
success: true,
fail:false
}
}
3. 计算属性:
什么是: 自己不保存值,每次访问都要根据其他属性计算出来
何时: 要显示的值,需要根据其他属性动态计算才能获得时
如何:
- 定义计算属性:
computed:{
计算属性名(){
根据其他属性,返回计算结果
return ... ...
}
}
- 绑定时: 和普通属性完全一样,不要加()
vs methods
:
methods
: 调用时,必须加(),调用几次,就重复计算几次
computed
: 绑定时,不加(),即使多次绑定,也只计算一次。vue会缓存计算属性的计算结果
总结: 如果更关心值/结果,优先选计算属性
如果更关心操作/执行过程,优先选方法
4. 自定义指令:
如果13种指令不够用,可自定义指令:
如何:
- 定义指令:
Vue.directive(
"指令名",//不写v-前缀
{
inserted(elem){//当拥有该指令的元素被添加到DOM树后自动执行
//elem: 接住当前标有该指令的DOM元素对象
对elem执行各种想要的DOM操作
}
}
)
- 使用指令:
<ANY v-指令名>
当该元素被加载到DOM树上后,自动执行指令中的inserted
5. 过滤器:
什么是: 对从模型中绑定来的原始值,进行再加工后,再显示
何时: 如果模型中的原始值不能直接使用
如何:
- 定义过滤器:
Vue.filter("过滤器名", function(value,形参1,...){
//value会接住要处理的原始值
return 改造后的新值
})
- 使用过滤器:
在绑定时:
{{原始模型变量|过滤器(实参1,...)|下一个过滤器 }}
:属性="原始模型变量|过滤器(实参1,...)|下一个过滤器"
6. axios:
什么是: 基于Promise的专门发送http请求的函数库
何时: 今后在vue中发送ajax请求首选axios
为什么:
- 手写ajax四步/封装自定义函数
- jQuery: $.ajax() —— Vue中没有jQuery
- Vue官方曾经提供了专门发送ajax请求的组件:
vue-resource
——官方不推荐使用 - Vue官方推荐
axios
作为Vue中标准的发送ajax请求的组件
如何:- 下载并引入:axios.min.js
内存中,就多出一个axios对象,有两个方法: get() post() - 发送get请求:
- 下载并引入:axios.min.js
axios.get("url",{
params:{
uname: "dingding",
upwd:"123456"
}
}).then(function(res){
//res是经过axios再封装的响应对象,不仅是result
//result: res.data才是从前的result
})
发送post请求:
axios.post("url","uname=dingding&upwd=123456")
7. 组件:
什么是: 拥有专属的HTML,CSS,js和数据的独立页面区域
为什么: 重用!
何时: 只要一个页面功能,需要反复使用时
如何:
- 定义组件:
Vue.component(
"组件名",//不要用驼峰命名,而用"单词-单词"
{
template:"#tplID", //找到要反复使用的HTML片段
data:function(){//每次重复创建组件时,都自动调用data函数,为本次组件创建一个专属的模型对象
return { 模型数据 }//类似于以前的data
},
methods:{ 方法/事件处理函数 },
computed:{ 计算属性 },
watch:{ 监听函数 }
}
)
HTML片段都要保存在<template>
元素中并其一个唯一的id
2. 使用组件:
其实vue中的一个组件,就是一个可重复使用的自定义标签而已。组件名其实就是一个标签名:
<组件名></组件名>
会被template
的HTML片段代替!
day03
1. *****组件化开发
什么是组件化开发: 今后一个网页都是由组件组成的
拿到网页,先划分组件,再分组件开发,最后再拼接成一个网页
为什么:
- 团队协作开发
- 松耦合
如何:- 拿到网页,先划分组件
- 定义组件
- 将组件拼回主页面中
问题: 组件分类:
- 根组件: 一个页面中只有一个的组件:
new Vue({
el:"#app",
data:{ ... }
})
- 全局组件: 可出现在任意位置的组件
Vue.component("组件名",{
template:"#tplxxx",
data(){ return { ... } }
})
- 子组件: 只能出现在规定父组件内的组件
如何: 2步- 将Vue.component降级为普通的js对象
//Vue.component("todo-add",{ var todoAdd={ template:"#tplTodoAdd", data(){ return { ... } } }
- 在父组件的{}中的components下添加子组件对象:
Vue.component("todo",{ template:"#tplTodo", data(){ return { ... } }, components:{ todoAdd } //vue会自动将todoAdd -> <todo-add> })
*****组件间传参:
父->子:
问题: 父组件的成员,子组件无权直接使用
解决: 2步
1. 在子组件对象中添加props属性:
var 子组件={
template:"#tpl子组件",
props:[ "自定义属性名" ]
data(){ return {...} }
}
后果: 2个:
1. 为子组件标签添加了一个自定义扩展属性,用于接收父组件的值。
<子组件 自定义属性="">
2. 子组件对象中多处一个同名的模型变量,可用于获取外部传入的属性值,在内部执行操作。
2. 在父组件的<template>中
<子组件 :自定义属性="父组件的数据"></子组件>
将父组件data中的数据通过绑定方式,传递给子组件的自定义扩展属性。
其实,父子组件用的还是同一个数据对象,任何一方修改,另一方都会受影响。
2. *****SPA
Single Page Application
什么是: 整个应用程序只有一个完整的HTML页面文件
单页面应用中所谓的“页面”,其实就是组件
由一个路由器根据URL地址中的锚点地址不同,选择不同的组件替换
vs 多页面应用:
单页面应用的优点:
请求次数: 多页面应用每更换一次页面就需要重新发送请求
单页面应用每更换一次页面,只需要从本地加载组件即可,不用重复发请求
资源共用: 多页面应用每更换一次页面,都需要重复请求相同的资源
单页面应用仅在首次加载时请求一次资源文件,之后更换页面,因为不是更换整个html文件,所以共用资源无需重复下载。
效率: 多页面应用,每次更换页面需要重建整棵DOM树,效率低
单页面应用,每次更换页面无需重建DOM树,仅是替换部分子树片段即可。效率高。
页面过渡效果: 多页面应用不可能实现页面过渡效果
单页面应用可以实现页面过渡效果
单页面应用的缺点:
- 首屏加载慢,要下载全部资源
已经解决: 在路由中设置延迟加载 - 不便于搜索引擎优化
实现单页面应用: vue-router.js
- 先创建一个唯一的完整的index.html
引入vue-router.js
在div#app
中添加一个<router-view>
标签,用于为将来要加载的"页面"组件占位 - 分别创建多个“页面”组件对象和模板
“页面”组件对象必须以子组件形式创建 - 定义路由字典:
路由字典:保存一组路径与组件对象对应关系的数组
var routes=[
{path:"/相对路径名", component: "页面"组件对象 }
]
- 定义路由器对象,将路由字典放入路由器中:
才是真正负责导航/替换页面内容的对象
var router=new VueRouter({ routes })
- 将路由器对象,加入当前页面的根组件
new Vue
中
new Vue({
...,
router,
...
})
嵌套路由:
何时: 多个页面中包含相同的区域(页头,页脚,导航)时
如何: 2步:
- 将多个页面共用的部分,保存在一个新创建的组件中
新组件同时包含<router-view>
- 定义路由字典:
//home: 是保存相同部分的组件
{path:"/",component:home,children:[
{path:"/",component:index},//默认路径 /
{path:"/index",component:index},// /index
{path:"/details",component:details} // /details
]},
//login和之前页面没有相同部分
{path:"/login",component:login}
加载时:
#/ /=="/" 先加载home页头
/=="/"
再加载index替换home中的<router-view>
#/details /=="/"
先加载home页头
/details="/details"
再加载details替换home中的<router-view>
#/login /=="/"
先加载home页头
没有/login
撤掉home页头
/login="/login" 只加载login
day04
1. 路由跳转:
HTML中: 所有a换成<router-link to="路径"></router-link>
运行时,自动翻译为<a href="#/路径"></a>
js中: this.$router.push("路径")
$router
就是var router=new VueRouter()
路由器对象
要执行跳转这个动作,只能借助$router
凡是以$
开头的,都是Vue内置的对象
2. 路由传参:
2步:
- 在路由字典中配置支持参数的相对路径:
{path:"/details/:lid",component:Details,props:true}
/:lid: 将来请求details页面时必须携带一个lid参数
比如:/details/5
在details
页面中获取参数:
this.$route.params.lid
如果定义了props:true
,lid
参数会自动传递给props
中同名的属性:props:["lid"]
this.lid=5
- 跳转时:
<router-link to="/details/5"
4. 组件生命周期:
什么是: 一个组件创建的过程
包括: 4个阶段:
-
create
: 创建阶段:
创建组件对象,以及模型对象data
2个钩子函数:
beforeCreate()
创建对象前触发
created()
创建对象和data数据后触发
有data
可以axios
发送ajax请求
没有虚拟DOM 暂时不能操作DOM元素 -
mount
: 挂载阶段
生成虚拟DOM树,绑定数据到真实的DOM树上
beforeMount()
挂载阶段开始前自动触发
mounted()
挂载后自动触发
有data
可以axios发送ajax请求
有虚拟DOM
,可执行DOM操作 -
update
: 更新阶段
当组件的模型数据被更新时自动触发
beforeUpdate()
updated()
-
destroy
: 销毁阶段
除非调用专门的destroy
函数,才能触发destroy
阶段
beforeDestroy()
destoryed()