一. axios
虽然在jq中$.ajax()函数已经很好用 在vue中几乎很少使用DOM操作,自然也就很少使用jQuery 所以,几乎vue中不会把jquery引入项目中 所以,在vue中就无法无法使用$.ajax()
axios: 第三方开发的,基于Promise技术的,专门发送http请求的一组函数库
何时使用:只要在vue中发送ajax请求,都用axios
使用:
(1)下载并引入axios.js <script src="js/axios.js">
(2)发送请求:
get请求:axios.get("url",{params:{参数:值,...}}).then(result=>{
result.data //服务器端返回的数据
})
post请求:axios.post("url","参数1=值&参数2=值"...).then(result=>{
result data //服务器端返回的数据
})
强调:框架中使用ajax请求相关的函数,回调函数一律用箭头函数
原因: 所有回调函数中的this默认都指向window 而我们希望框架中this永远指向当前框架对象本身!
解决: 将回调函数改为箭头函数,使回调函数中的this可以和外部的this保持一致!统一指向当前框架对象(new Vue())
get请求:有参数和无参数
post请求:
二. 生命周期
项目中所有的js代码必须写在new Vue()内部 new Vue()外部不能写任何js代码 但是,有些需要在页面加载完成后就自动执行的代码写哪儿
错误:
(1). DOM时: 都写在window.onload中!但是new Vue()没有window.onload
(2). jq时: 都写在$(document).ready(function(){ ... })!但是new Vue()也不用jquery
正确:
其实每个new Vue()对象创建的过程都会经历一个生命周期,在生命周期的每个阶段,都会自动触发一个类似于window.onload这样的回调函数!
vue的生命周期包括: 4个阶段
(1)创建create(对象)——必经阶段 (创建对象)
a. 创建new Vue()对象
b. 引入并创建data对象,同时请保镖——可以操作data中的变量
c. 引入methods中的函数——可以调用methods中的函数
d. 暂时不会扫描DOM树,生成虚拟DOM树——暂时不能执行DOM操作!
(2)挂载mount(页面内容)——必经阶段 (生成虚拟DOM树,挂载数据)
a. 扫描真实DOM树,生成虚拟DOM树
b. 首次加载数据到页面中显示!
c. 可以执行DOM操作了!
(3)更新update——只有当data中的数据被改变时才触发
(4)销毁destroy——只有主动调用$destroy()销毁当前new Vue()时才触发
其实每个阶段前后,都会自动触发一个回调函数——钩子函数
共8个钩子函数
beforeCreate() 创建前
(1). 创建阶段create
created()
beforeMount() 挂载前
(2). 挂载阶段mount
mounted() —— 因为此时既有data对象,又有虚拟DOM树,所以今后axios请求都要放在mounted()中才保险
beforeUpdate() 更新前
(3). 更新阶段update
updated()
beforeDestroy 销毁前
(4). 销毁阶段 destroy
destroyed
三. 组件
专属HTML+CSS+JS数据的可重用的页面独立功能区域
为何:重用
如何:
(1)添加自定义组件
Vue.component("组件名",{
//每个组件都是一个缩微版的new Vue({})
//两处不同:
template:`<唯一父元素包裹></唯一父元素包裹>`,
data(){ //可被反复调用
//每次调用时都会新创建一个data对象
return {//new Object()
变量:初始值
}
},
/******同new Vue()的部分*******/
methods:{ ... },
computed:{ ... },
钩子函数(){ ... },
... ...
})
(2)在HTML中使用组件:组件其实就是一个可重用的自定义HTML标签而已 <组件名></组件名>
原理:
(1)当new Vue扫描页面时,发现不认识的HTML标签,会回vue对象中查找
(2)找到同名组件,先用template内容代替自定义标签
(3)为这个区域创建一个缩微的new Vue()对象副本,并创建一个当前组件专属的data对象副本,包含专属的变量
(4)结果: 这个小的组件区域,就拥有了专属的HTML+数据+一个缩微版的new Vue()组件对象。
示例一个组件反复使用:
四.组件化开发
拿到一个页面后,都是先将一个大的完整的页面划分为多个功能区域(组件)
如何:
(1). 拿到页面后先划分组件区域:
a. 从上到下,从左到右,从外向内的原则,按区域划分
b. 按是否重用划分!
(2). 为每个组件创建独立的组件文件(.js,将来是.vue),其中包含组件的HTML和js内容。
(3). 在主页面或父组件中,使用<组件名/>引入子组件到父组件或页面中。
结果: new Vue()扫描页面时,只要发现不认识的标签,就会去查找同名的组件。就会用组件的template代替不认识的标签的位置。把所有不认识的标签代替完,所有组件就都被引入到页面中显示了。
问题: 有些组件只能在它的父组件内使用,才有意义 不能超出父组件范围使用!但是, Vue.component()创建的组件是没有限制的。可以用在网页的任何位置。
解决: vue中的组件分三大类:
(1)根组件:new Vue()
整个项目可能只有一个new Vue()
(2)全局组件: Vue.component()
可以用在项目的任何位置,没有限制!
(3)子组件:
a. 什么是: 一个规定只能在某个父组件内才能使用的组件
b. 何时: 今后只要限制一个组件只能在规定的父组件内才能使用,就要用子组件
c. 如何: 3步:
1). 创建子组件对象:
a. 就是一个很普通的js对象
b. 要求对象的内容要和vue组件规定一致!
c. 对象名暂时使用驼峰命名!不要用-
var 子组件对象名={
template:`HTML片段`,
data(){ return { .. }},
methods:{ ... },
... ...
}
2). 在父组件中添加components成员,其中包含当前父组件下的所有子对象对象名。
父组件对象:{
template:`HTML片段`,
data(){ return { ... }},
... ... ,
components:{
子组件对象名, ... , ...
}
}
强调:
a. 子组件文件,必须在父组件文件之前提前引入!
b. components会自动将js中驼峰命名的子组件对象名,翻译为-分割的子组件标签名。所以将来依然是在js中用驼峰,在HTML中用-。之间的差异由components自动翻译!
3). 在父组件的template中使用<子组件标签名/>引入子组件内容。
组件间传值:
(1). 问题: 待办事项列表两大部分功能。添加区域,负责向待办事项列表中添加一个新任务。列表区域,负责显示出待办事项列表中的内容。也就是说,todoAdd和todoList两个组件都需要用到同一个待办事项列表(数组)。待办事项列表的数据应该保存在哪个组建中?
(2). 解决: 将共用的数组保存在父组件中一份,方便所有子组件使用!
(3). 问题: Vue中子组件不能直接使用父组件内的数据!因为每个组件的数据是专属的!不共享的!
(4). 解决: Vue中组件间可以传值!——父给子
a. 父把数据放到孩子身上: ——才用绑定属性值的方式给
父组件对象: {
template:`
......
<子组件标签 :自定义属性名="父的变量"></子组件标签>
......
`
}
b. 孩子从自己身上父放数据的位置取出数据:
子组件对象:{
props:[ "自定义属性名" ] //properties
}
c. 结果: props中的自定义属性名用法和data中自己的变量完全一样!data中的变量怎么用,props中的自定义属性就怎么用!
1). 在子组件的template中HTML内: 可直接在指令或绑定语法中用"自定义属性名"来使用父组件传来的数据。
2). 在子组件对象js内: 任何位置都可用"this.自定义属性名"使用父组件传来的数据!
五.SPA 单页面应用
整个应用程序只有一个完整的HTML页面。其它所谓的"页面",其实都是一个一个的组件
几乎所有PC端或移动端的项目都用单页面应用来做
缺点: 首屏加载速度极慢 解决: 懒加载(待续...)
如何实现: 3大步:
(1)创建唯一完整的HTML页面
a. 必须是一个支持new Vue()的标准页面结构
b. 引入vue单页面应用的核心组件vue-router.js
vue路由器
<script src="js/vue-router.js">
vue路由器
c. 在<div id="app">内某个位置,添加<router-view>标签,为将来可能加载外页面中的其它"页面"组件占位。
<router-view>
路由器视图
(2)规划项目中共包含几个页面,每个页面都要创建一个独立的子组件对象文件:
var 页面名={
template:`页面内容`,
data(){ return { ... } },
... ...
}
(3)在独立的js文件中创建路由器vuerouter对象,
a. 先定义路由字典数组:
1). 什么是路由字典: 集中保存,每种组件与不同路径对应关系的数组。
2). 如何:
路由字典
var routes=[
路径 组件
{path:"/", component: 首页组件对象},
{path:"/details", component: 详情页组件对象},
{...},
...
]
b. 创建路由器对象:
1). 路由器: 专门自动①监视地址栏变化,并能根据地址栏的新路径,②找到对应的组件,③替换页面中<router-view>(路由器视图)的位置,的小程序。
2). 如何:
var router=new VueRouter({ routes })
路由器 Vue路由器
c. 路由器对象必须引入到根组件new Vue()才能发挥作用!
new Vue({
el:"#app",
router //路由器
})
原理:
(1). 路由器router对象被加入到唯一html页面内的new Vue()中,就会监视当前HTML页面所在的路径。
(2). 一旦浏览器地址栏中路径发生变化, router就会立刻获得当前新路径,自动去路由字典routes中查找是否有匹配的路径。
(3). 只要找到路由字典中和当前地址栏中匹配的路径,就自动去内存中找对应的组件对象
(4). 只要找到组件对象,就会用组件对象的内容,替换HTML页面中占位符<router-view>的位置!
路由器视图
(5). 最后用户就看到了对应组件的内容。
为什么使用#/作为客户端导航的标志:
(1). 如果在浏览器地址栏中输入新地址,默认浏览器都会向服务器端发送请求!
(2). 但是,vue spa应用中,因为早就把所有页面的组件都下载到了客户端本地!所以,当修改地址栏路径时,不应该再向服务器发送请求!而应该交给网页本地的路由器对象,解析新地址,加载对应的组件
(3). url标准中只有一种地址是客户端导航!——锚点地址!当在浏览器内切换锚点地址时,浏览器时不会向服务器端发送请求,而是在当前页面内跳转——复习第二阶段锚点地址
(4). 所以,vue 单页面应用为了避免浏览器向服务器发送请求,才用的"#/相对路径"锚点地址方式作为客户端导航!
公共的页头怎么放?
(1). 页头不是一个独立的"页面",所以不能加入到路由字典中作为页面使用
(2). 页头通常作为一个全局组件,可用在任何位置!
(3). 两种情况:
a. 如果希望所有页面都有统一的页头,应该把<页头>放在html页面中<router-view>上方!
路由器视图
b. 如果希望有的页面有页头,有的页面没有页头(登录、404),应该分别把<页头>只放在那些都需要显示页头的组件内的template顶部
模板
404页:
(1). 404页也是一个可被用户独立浏览的页面,所以也要做成页面组件文件
(2). 也要把404页面加入到路由字典中,只不过path:"*"
路径
(3). 结果: 今后访问除路由字典外其余错误的路径都要自动跳转到404页面。
"页面"跳转:
(1). HTML中写死的跳转:
<router-link to="/相对路径">文本</router-link>
(2). 在js中用程序跳转:
this.$router.push("/相对路径")
页面跳转时传值:
(1). 改造路由字典中的路由地址,让它可以携带参数到下一个页面
路径 组件 属性(properties)
{path:"/相对路径/:变量名", component:组件名, props:true}
a. /:变量名 允许当前路径携带一个参数值到下一个页面
b. props:true 让地址栏中的参数值,自动变成下个页面中props中的变量。结果,在下个页面中可用this.变量名方式,快速获得地址栏中的参数值。
(2). 在跳转时,拼接路径: "/相对路径/参数值"
强调:
a. 不要用?连接参数值
b. 不要加: ,/后直接写参数值!
(3). 在下个页面中:
a. 先props:[ '变量名' ],接住地址栏中的参数值
b. HTML中: 可用{{变量名}},可获得地址栏中传来的参数值
c. js中,可用this.变量名 获得地址栏传来的参数值
(4). 坑: 一旦一个路径变成携带参数的路径,则今后跳转时,必须携带参数!如果不携带参数,就与path中的规定不符,属于无效路径!跳转到404!
手工SPA单页面应用demo