建设网站不会写代码,上海做网站建设,ps设计网站首页界面,北京哪个公司做网站文章目录1. 简介2. 第一个Vue程序3. 指令3.1 判断循环3.2 操作属性3.3 绑定事件3.4 表单中数据双向绑定3.5 其他内置指令3.6 自定义指令4. 组件4.1 全局注册4.2 局部注册4.3 组件通讯4.4 单文件组件5. 组件插槽5.1 单个插槽5.2 具名插槽5.3 作用域插槽6. 内置组件6.1 component…
文章目录1. 简介2. 第一个Vue程序3. 指令3.1 判断循环3.2 操作属性3.3 绑定事件3.4 表单中数据双向绑定3.5 其他内置指令3.6 自定义指令4. 组件4.1 全局注册4.2 局部注册4.3 组件通讯4.4 单文件组件5. 组件插槽5.1 单个插槽5.2 具名插槽5.3 作用域插槽6. 内置组件6.1 component组件6.2 keep-alive组件6.3 transition组件7. axios网络通信7.1 第一个Axios7.2 各种请求方式7.3 跨域问题8. Vue的其他配置8.1 计算属性8.2 监视属性8.3 过滤器9. 生命周期10. vue-cli10.1 简介10.2 创建项目10.3 项目目录结构11. webpack11.1 简介11.2 安装使用12. vuex12.1 vuex原理12.2 基本使用12.2 四个map方法12.3 模块化命名空间13. vue-router13.1 简介13.2 简单使用13.3 单文件注册路由13.4 路由跳转/传递接受参数13.5 两个钩子13.6 路由守卫13.7 路由两种模式14. 组件库1. 简介
Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层不仅易于上手还便于与第三方库或既有项目整合。
Vue是个MVVM框架使用了模块化虚拟DOM
MVVMModel-View-ViewModel 核心是ViewModel层负责转化Model中的数据对象来让数据变得更容易管理和使用
作用
ViewModel层向上与视图层View进行双向绑定ViewModel层向下与Model层通过接口请求进行数据交互
MVVM模式和MVC模式一样主要目的是分离视图View和模型Model有一下好处
低耦合可复用独立开发可测试
⭐解释思想很重要
双向数据绑定 –(JSON)
View(HTML,CSS,Templates) - - ViewModel(JavaScrip,Runtime,Complier) --(AJAX) Model (Java业务逻辑层-数据库)
前端页面 即时运行即时编译 后端 和JSP本质不一样了如果前端给我们页面还要${key}这个key还要我们Java程序员写上去而Vue我们只需要用JSON把数据返回给前端就行了前端根据模板{{ }}进行显示就行了这个模板我们不需要我们Java程序员去改去写 完全解耦了View层 和Model层这个是至关重要的前后端分离的重要一环 Vue.js就是MVVM的实现者核心就是实现类DOM监听和数据绑定 笔记前端笔记 2. 第一个Vue程序
!DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleTitle/title/head
bodyh1Java/h1 !-- 而这里改变就需要使用JS操作DOM对象重写DOM对象而且需要刷新页面才能看到改变--!-- View层 模板--div idapp{{ message }} !-- 4.从模板取数据这里不需要刷新页面就可以根据数据变化响应前端--/div!-- 1.导入vue.js--script srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/scriptscript// 2.new Vue对象var vm new Vue({el: #app, // 3.绑定元素data: { // Model 数据message: Hello,Vue!}});/script
/body
/htmlVue对象7个常用属性
eldatatemplatemethodsrandercomputedwatch 3. 指令
3.1 判断循环 指令带有前缀v代表他们是Vue提供的特殊特征 v-if v-elsev-else-if 根据表达式的真假切换元素的显示和隐藏操作DOM元素直接把DOM元素移除了
div idapph1 v-ifflagyes/h1 !-- 判断显示那个--h1 v-elseNo/h1p v-ifshow AA/p !-- 类似JSP里面的JSTL标签--p v-else-ifshow BB/pp v-elseC/p
/divscriptvar vm new Vue({el: #app,data: { flag: true,show: A}});
/scriptv-for
div idapp!-- li v-foritem in items --li v-for(item, index) in items !-- 反着写,item是数组里面的每个元素,index是下标,0开始,注意是()括号--{{item}} --- {{index}}/li
/divscriptvar vm new Vue({el: #app, data: { // 数组里面还可以是对象 items: [ {message:Java}, {message:C} ]模板里面直接item.messageitems: [1,2,3,4] }});
/script3.2 操作属性
v-bind 设置元素是属性 冒号后面代表属性名 v-bind:属性名表达式
div idapp{{ message }} !-- 模板中支持JS语法但只能一条语句{{ message.reverse() }} --span v-bind:titlemessage !-- 绑定鼠标在字上面显示的内容--鼠标悬停几秒查看此处动态绑定提示信息/spana v-bind:hrefurl图片/a!-- 动态添加class,isActive是data里面的一个数据-- p v-bind:classisActive:active:../pp v-bind:class{active:isActive}../p !-- 推荐对象这种--
/diva v-bind:hrefurl图片/a 简写a :hrefurl图片/a 3.3 绑定事件
v-on 绑定事件监听DOM事件
div idappbutton v-on:clicksayHi点击我/button !-- 想要绑定什么事件冒号后面写就行了--
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
scriptvar vm new Vue({el: #app,data: {message: Hello!},methods: { // 方法必须定义到Vue的methods对象中sayHi: function () {alert(this.message); // this指vm这个对象}}});
/scriptbutton v-on:clicksayHi点击我/button v-on:都是相同的所以可以简写button clicksayHi点击我/button v-on还可以传递参数事件修饰符等 事件修饰符 .prevent 阻止标签的默认行为.stop 阻止事件的冒泡.once 事件只触发一次 div idappbutton clicksay(haha)自定义参数/button !-- .prevent阻止a标签的默认行为--a href.. click.preventsayHi/a !-- 键盘事件keyupkeydown.enter按下回车就会执行sayHi()方法hdelete,esc,space,tab,up,down-- input typetext keyup.entersayHi/
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
scriptvar vm new Vue({el: #app,methods: { say: function (str) {alert(str); },sayHi: function () {alert(Hi); }}});
/script还有audio标签里面的play(播放) pause(暂停) 事件等 3.4 表单中数据双向绑定 v-model 获取和设置表单元素的值 v-model 在表单是input,textarea,select…元素上创建双向数据绑定会根据控件类型自动选取正确的方式来更新元素
v-model会忽略所有表单元素的valuecheckedselected特性的初始值而总是将Vue实例的数据作为数据源你应该在JavaScrip在组件date中设置初始值
修饰符v-model.lazy v-model.number v-model.trim
div idappinput typetext v-model:valuemessage br !-- 输入的和后面的显示双向动态绑定--你输入的文本是{{message}} br性别input typeradio namesex valueboy v-modelstr 男 !-- 简写可以去掉v-model后的value--input typeradio namesex valuegirl v-modelstr 女 br你选中的性别的{{str}}爱好select namebobby v-modeltempoption disableddisabled value请选择/optionoption valueJavaJava/optionoption valuePythonPython/optionoption valueCC/option br/select你选中的爱好是{{temp}} !-- 神奇temp就是value--
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
scriptvar vm new Vue({el: #app,data: {message: ,str: // 绑定的是value属性值吧temp: Java // 这里设置为这默认选“请选择”设置为Java默认选“Java”而在option中使用selected没用}});
/script3.5 其他内置指令 v-show 根据表达式的真假切换元素的显示和隐藏和v-if效果一样但这个v-show是操作disabled属性DOM元素始终都在 频繁切换建议使用v-show 因为频繁操作DOM消耗大。 img src地址 v-showage18/ !-- age是data里面的数据--v-test 设置标签的文本值。例如 h1 v-testmessage/h1缺点会全部替换掉。解决可以使用{{ }}语法 v-html设置标签的innerHTML可能会有XSS攻击 v-cloak 没有值配合css可以防止vue介入慢而引起的页面闪烁 v-once 没有值在初始动态渲染后都视为静态内容了 v-pre 没有值跳过所在结点的编译过程可以利用它跳过没有使用指令差值语法的结点加快编译 ref 属性这个可以简洁操作DOMid的替代者。如果写在组件标签上则拿到的是ref属性所在标签对应子组件的实例对象 h1 reftitle/h1
button clickshowDom点我展示上面的DOM元素/buttonscriptnew Vue({methods: {showDom() {console.log(this.$refs.title); // 类似元素的document.getElementById(id)}}})
/script3.6 自定义指令
directives注意自定义函数里面的this不是vm了而是window
div idapph1 v-bign/h1
/divscriptnew Vue({el: #app,data: {n: 10 },directives: { big: { // 自定义指令v-big就需要手动操作DOMbind() {}, // 指令和元素成功绑定时这三个函数都能收到那两个参数inserted() {}, // 指令所在元素被插入页面时update() {} // 指令所在的模板被重新解析时},// 简写什么时候被调用呢// 1.指令和元素成功绑定时(一上来) 2.指令所在的模板被重新解析时(即上面的bind和update)big(element, binding) { // 简写element.innerText binding.value * 10;}}})Vue.directive(, {}); // 全局的自定义指令 或者Vue.directive(, 回调函数);
/script4. 组件
组件是可复用Vue实例就是可以重复使用的模板局部功能代码和资源的集合
4.1 全局注册
简单的
div idappmy-com/my-com !-- 这里就会显示列表Hello--
/divscript// 全局定义一个组件在哪个组件中都可以使用// my-com就是组件的名字如果这里使用驼峰命名法时上面标签使用要转化为小写加-的形式Vue.component(my-com, { template: liHello/li});new Vue({el: #app});
/script动态数据
div idapp!-- v-bind:接受参数遍历参数 --my-com v-foritem in items v-bind:tempitem/my-com
/divscript// 在组件中改变props中变量变化根组件中不会变// 特殊的数组对象可以改变其内容。父子组件的所有prop都是单向向下绑定的Vue.component(my-com, { props: [temp],template: li{{temp}}/li // 这里不能直接访问到下面的data数据要使用props接受上面绑定是动态显示});new Vue({el: #app,data: {items: [Java, Linux, C]}});
/script4.2 局部注册
注册的时候是什么名标签里面用就得用什么名
new Vue({el: #app, // 局部注册只能在这个根实例中使用components: {my-com-a: { // 横线命名要加单引号template: h1{{ title }}/h1,data() { // data: function{} data(){}后面是ES6的写法。写成方法是为了多个组件实例数据不相互影响return { title: 我是标题A }}}MyComB: { // 这样可以不用加单引号html中使用时会自动映射为上面那种命名template: h1{{ title }}/h1,data() {return { title: 我是标题A }}}}
})
// 单独配置组件的选项对象
// 每次调用Vue.extend就是调用VueComponent的构造函数每次返回的都是一个全新的VueComponent即组件实例对象
// var MyComA Vue.extend({ }) 简写: var MyComA { }简写的话注册组件的时候框架会帮我们调用Vue.extend()
var MyComA {/* */}
var MyComB {/* */}
new Vue({el: #app,components: {my-com-a : MyComA, //或者MyComA: MyComA (推荐单词首字母都大写标签里使用也是但需要在脚手架里面使用)my-com-b : MyComb,}
});
// 简写
new Vue({el: #app,components: {MyComA, // 当组件名和属性变量变量的话可以简写, 这样是ES6的写法MyComb,}
});4.3 组件通讯 父组件向子组件传值⭐ 通过props选项接受父组件的传值 父组件
div idapp !-- 父组件设置传值--my-com title哈哈/my-com 传递静态的值my-com :title哈哈/my-com 动态绑定,绑定静态字符串值需要加单引号my-com :titlemsg/my-com msg父组件中data的值
/divscript//子组件Vue.component(my-com, {props: [title], // 命名推荐驼峰命名法父组件绑定时需要使用带横线的命名template: h3{{ title }}/h3props: { // 类型限制,传来的title属性是字符串类型的话才进行接受title: String } props: { // 完整写法title: {type: String,required: false,default: 默认值} } })// 父组件...
/scriptprops是只读的如果强转修改Vue有警告。父子组件的所有prop都是单向向下绑定的 如果真的想要改的话请复制一份到data中然后再去修改data中的数据。因为先接受props再去加载data 子组件向父组件传值 通过自定义事件实现⭐ 绑定自定义事件 第一种方式在父组件中Demo 事件名回调方法 第二种方式在父组件中this.$refs.demo.$on(事件名,回调方法) 注意第二种方式绑定自定义事件时回调函数要么配置在methods中要么用箭头函数否则this指向会出问题 触发自定义事件在子组件中this.$emit(事件名,数据) 解绑自定义事件this.$off(事件名) div idapp !-- 父组件设置传值--h3购物车/h3product-itemv-forproduct in products:keyproduct.id 下面不用接受key参数只是个标识:titleproduct.titlecount-changeonCountChange 绑定自定义事件/product-itemp 总数为 {{totalCount}} /pproduct-item ... refproductItem/product-item !-- 或者这样绑定自定义事件这样更灵活点--product-item ... click.native../product-item !-- 如果给组件绑定元素的事件需要native修饰符--
/divscript// 子组件Vue.component(product-item, {props: [title],template: divspan商品名称{{ title }}。商品个数{{ count }}/spanbutton clickcountIns11/buttonbutton clickcountIns55/button/div,data() {return {count: 0}},methods: {countIns1() {//this.$emit(count-change); // 通知父组件命名建议采用带横线的方式this.$emit(count-change, 1); // 触发自定义事件可以带多个参数this.count;},countIns5() {this.$emit(count-change, 5);this.count 5;// 这样可以解绑自定义事件再怎么触发都没用了解绑多个需要传数组,解绑全部可以不传参数// this.$off(count-change) }}});// 父组件回调是留在父组件这里的例如onCountChangenew Vue({el: #app,data: {products: [{id: 1, title: 苹果},{id: 2, title: 香蕉},{id: 3, title: 梨子}],totalCount: 0},methods: {onCountChange(productCount) {this.totalCount productCount;}},mouted() {// 或者这样绑定自定义事件这样更灵活点比如延迟几秒在进行绑定...this.$refs.productItem.$on(count-change, this.onCountChange);this.$refs.productItem.$once(count-change, this.onCountChange); // 只能用一次一次性}});
/script非父子组件传值 通过父组件进行数据的中转 兄弟组件 如果只有一层的话使用父组件进行中转很简单如果组件层数很多的话将会变得非常繁琐不建议 全局事件总线 ⭐ 独立的事件中心用于管理不同组件间的传值操作 任意两个组件都可以通信开发中用的最多。 安装全局事件总线 // 标准的写法在src/main.js中
// 在其他组件中直接this.$eventBus.$emit()this.$eventBus.$on()所有的组件实例对象即vcvm都能看到
new Vue({el: #app,render: h h(App),beforeCreate() {// 安装全局事件总线往Vue的原型对象上放的所有的组件实例对象都有this就是根vmVue.prototype.$eventBus this; }
})使用事件总线最好用完在beforeDestory钩子中解绑当前组件所用到的事件 div idapp h3购物车/h3product-item title苹果/product-itemproduct-total/product-total
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
script// 子组件Vue.component(product-item, {props: [title],template: divspan商品名称{{ title }}。商品个数{{ count }}/spanbutton clickcountIns11/button/div,data() {return {count: 0}},methods: {countIns1() {// 触发自定义事件注意不是this而是this.$eventBus可以被任意组件访问从而实现了数据的中转this.$eventBus.$emit(count-change, 1);this.count;}}});// 进行商品统计的 子组件Vue.component(product-total, {template: p总数为{{ totalCount }}/p,data() {return {totalCount: 0}},mounted() { // mounted钩子函数最好被挂载后进行绑定自定义事件// 给this.$eventBus绑定对应事件 (相当于接受上面的数据了)回调函数如果直接写的话要用箭头函数this.$eventBus.$on(count-change, (productCount) { this.totalCount productCount;})},beforeDestory() {this.$eventBus.$off(count-change);}});
/script4.4 单文件组件
组件配置中datamethodswatch中的函数…它们的this都是VueComponent实例对象
Test.vue表示一个独立的组件一般是MyTest用单词首字母都大写的这种命名
!-- 下面是组件的单文件写法。使用Vue.component()注册全局组件容易命名冲突而且没有语法提示使用css不方便 --
template !-- 模板区--h2 classtest-aTEST {{msg}}/h2
/templatescript /* 脚本区 */export default {name: Test, // 一般和文件名保持一致props: [xxx],data() { msg: 示例文本 }, // 该组件的数据methods: { }, // 注册对应的方法computed: { } // 计算属性}
/scriptstyle scoped /* 样式区scoped防止组件间样式冲突问题 */.test-a {color: red;}
/styleApp.vue App一般是根组件一人之上万人之下管理所有的子组件
vm - App.vue - Student.vue - Person.vue..- School.vue - ...templatedivh2哈哈/h2Test/Test/div
/templatescriptimport Test from ./Test.vue // ES6的模板导入方案export default {name: App,components: { // 局部注册组件上面模板就能使用导入的子组件了Test}}
/scriptmain.js 人口文件创建vm
import App from ./App.vuenew Vue({el: #root, // 指定为哪个容器服务template: App/App, // 这个不写也行或者在下面的id为root的div中写App/App或者render: h h(App)components: {App} // 只注册APP主组件即可因为App管理所有的子组件
})⭐在脚手架中自动引入的vue是残缺版的vue即vue.runtime.esm.js里面没有模板解析器因为最终使用webpack打包发布的时候已经解析过了就不应该有模板解析器了体积不小只能用这个方式render: h h(App)而用template: App/App会报错。 因为vue.runtime.xxx.js没有模板解析器所以不能使用template配置项template属性需要rander函数接收到的createElement函数去指定内容。而vue文件里面的template标签里内容是由一个专门的独立模块vue-template-complier解析的这个脚手架帮已经我们引入了 index.html 单页面应用就这一共html
!DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.orgheadmeta charsetUTF-8titleTitle/title/headbody div idroot/div !-- 准备一个容器--!-- 这两行引入意义不大了因为使用脚手架会帮我们自动引入执行--script typetext/javascript src../js/vue.js/script script typetext/javascript src./main.js/script/body
/htmlvue单文件开发js模块化开发需要在脚手架环境下才能执行。 多个组件共享的配置可以抽取出来一个混合对象。例如export const hunhe { data(){...}, methods: {...} }。 局部{ mixin: [hunhe] } 全局Vue.mixin(hunhe) this.$nextTick(function() {}) 指定的回调方法会在Dom元素更新完毕后再去执行一般用于当数据修改后要基于更新后新的DOM进行某些操作时要在nextTick所指定的回调方法中执行。 5. 组件插槽
在Vue中我们可以使用slot元素作为承载分发内容的出口称为插槽可以应用在组合组件的场景中。
以前我们是使用props进行传递不太繁琐但也不算简单使用插槽更简单一点。
5.1 单个插槽
不使用插槽中间的内容会被抛弃使用插槽的话中间写的内容会替换组件中的slot标签
slot中可以设置默认值slot这是默认值/slot父组件中如果设置了插槽内容会被替换掉
挖个坑等着组件的使用者进行填充
div idapp!-- 不使用插槽中间的内容会被抛弃使用插槽的话中间写的内容会替换组件中的slot标签--my-com实例文本/my-commy-comh2苏瞳/h2 /my-commy-com这里是父组件的视图模板只能使用父组件的数据因为这部分是父组件来渲染的{{ parValue }}/my-com
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
scriptVue.component(my-com, {template: divh2组件标题/h2slot/slot/div});new Vue({el: #app,data: {parValue: 666}})
/script5.2 具名插槽
多个位置需要设置插槽需要给slot设置name
div idappcom-atemplate v-slot:header !-- template是个内容占位符并不是一个真正的标签在这个标签中才能使用v-slot--h1组件头部内容/h1 !-- 或者不写template标签直接这样h1 slotheader组件头部内容/h1 --/templatetemplate v-slot:default !-- 不写name默认是default或者不用template直接写就行--p内容1/pp内容2/p/templatetemplate v-slot:footer !-- 可以简写template #footer--p组件尾部/p/template/com-a
/divscriptVue.component(my-com, {template: divheaderslot nameheader/slot/headermainslot/slot/mainfooterslot namefooter/slot/footer/div});
/script5.3 作用域插槽
作用域插槽用于让插槽可以使用子组件中的数据
组件将需要被插槽使用的数据通过v-bind绑定给slot这种用于给插槽传递数据的属性称为插槽prop
组件绑定数据后插槽中需要使用v-slot接受数据
数据在组件的自身但根据数据生成的结构需要组件的使用者来决定
div idappcom-a!-- dataObj是包含了所有插槽prop的对象并不是直接接受value和num而是接受对象--template v-slot:defaultdataObj {{ dataObj.value }} {{ dataObj.num }}/template/com-a!-- 简写只有一个slot的话template标签可以省略v-slot属性写在com-a标签上default也可以省略掉--com-a v-slotdataObj !-- 或者这样也可以但不能都省略 my-com #defaultdataObj --{{ dataObj.value }}{{ dataObj.num }}/com-a!-- ES6的解构操作进行数据接受--com-a v-slot{ value, num } !-- 接受的是整个对象但我们希望只用整个对象里面的num属性, { num }也行--{{ num }}/com-a
/div!-- 注意这种语法是从2.6版本开始的--
script srchttps://cdn.jsdelivr.net/npm/vue2.6.10/dist/vue.js/script
scriptvar ComA {template: divp组件A的内容/pslot :valuechildValue :numchildNum默认值/slot/div,data() {return {childValue: 子组件内部数据,childNum: 666}}};new Vue({el: #app,components: {ComA}});
/script6. 内置组件
6.1 component组件
适用于多个组件进行频繁切换的处理例如选项卡操作
component用于将一个元组件渲染为动态组件以is属性值决定渲染那个组件。类似v-ifv-else-if的结构。
div idappbutton v-fortitle in titles clickcurCom title{{ title }}/buttoncomponent :iscurCom/component !-- is后面是要显示的组件名--
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
scriptvar ComA { template: divA组件内容/div }var ComB { template: divB组件内容/div }var ComC { template: divC组件内容/div }new Vue({el: #app,data: {titles: [ComA, ComB, ComC],curCom: ComA},components: {ComA, ComB, ComC}})
/scriptis属性在每次进行切换时Vue都会创建一个新的组件实例 组件的状态无法进行保留 // 下面三个组件进行切换时前一个输入框的内容就会消失
var ComA { template: divA组件内容input typetext/div }
var ComB { template: divB组件内容input typetext/div }
var ComC { template: divC组件内容input typetext/div }6.2 keep-alive组件
用于保留组件状态或避免组件重新渲染。
使用很简单
div idappbutton v-fortitle in titles clickcurCom title{{ title }}/buttonkeep-alive !-- 加上这个标签就行--component :iscurCom/component/keep-alive
/divinclude属性可以知道哪些组件进行保留状态哪些不保留
keep-alive includeComA,ComB,ComC !-- 静态是组件名--component :iscurCom/component
/keep-alivekeep-alive :include[ComA,ComB,ComC] !-- 动态绑定可以是数组/正则表达式可以在data中声明--component :iscurCom/component
/keep-alive6.3 transition组件
在Vue插入更新移除DOM时提供多种不同的方式的应用过渡动画效果。transitiontransition-group标签
style/* 进场类名(v-enter 进入的起点样式, v-enter-active 来的整个过程激活的样式, v-enter-to 进入的终点样式)离场类名(v-leave, v-leave-active, v-leave-to)官网有详细说 */.fade-enter-active, .fade-leave-active {transition: opacity .5s;}.fade-enter, .fade-leave-to {opacity: 0;}
/stylediv idappbutton clickisShow !isShow切换/buttontransition namefade !-- 用这个包起来即可,Vue会帮我们再合适的时机自动加入过渡和l动画主要靠CSS--p v-showisShow哈哈哈哈/p/transition
/divscriptnew Vue({el: #app,data: {isShow: true}})
/script7. axios网络通信
Axios是一个开源的可以用在浏览器端和NodeJS的异步通信框架主要作用的实现AJAx异步通信体积小
特点
从浏览器创建 XMLHttpRequests从 node.js 创建 http 请求支持 Promise API拦截请求和响应转换请求和响应数据取消请求自动转换JSON数据客户端支持防御XSRF
Vue.js由于是视图层框架所以不支持AJAX的通信功能为了解决单独开发了一个vue-resource的插件但这个进入2.0后就停止了改插件对的维护并**推荐了Axios框架少用JQuery,**因为操作DOM太繁琐 7.1 第一个Axios
安装
cdn script srchttps://unpkg.com/axios/dist/axios.min.js/scriptnpm npm install axios --save
data.json
{name:苏瞳java,url: http://baidu.com,address: {street: 含光门,city:陕西西安,country: 中国}
}test.html
div idvuediv{{info.name}}/divdiv{{info.address.street}}/diva v-bind:hrefinfo.url点我/a
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
script srchttps://unpkg.com/axios/dist/axios.min.js/script
scriptvar vm new Vue({el: #vue,data() { // 注意是data方法把数据return到data属性中 return {info: { }}},mounted() { // 发送get请求把获得的数据赋给info (类似JQuery的$.get)axios.get(data.json).then(response {this.info response.data})}});
/scripttest02.html
div idappbutton clickshowJoke点击显示笑话/buttonbutton clickshowJoke02点击显示笑话02/buttonp{{ joke }}/p
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
script srchttps://unpkg.com/axios/dist/axios.min.js/script
scriptvar vm new Vue({el: #app,data: {joke: },methods: {showJoke() {// 把this保存下来否则在then里面的方法this就变了var that this;axios.get(https://autumnfish.cn/api/joke).then(function (response) {that.joke response.data;});},showJoke02() {axios.get(https://autumnfish.cn/api/joke).then(response {// 使用箭头函数没有this就会往外找就找到了vmthis.joke response.data;});}});
/script7.2 各种请求方式
get/delete请求
第一个参数url第三个参数config
这里最好使用箭头函数这样this才是组件实例对象
// 向给定ID的用户发起请求
axios.get(/user?id12345).then(function (response) {// 处理成功情况console.log(response);}).catch(function (error) {// 处理错误情况console.log(error);}).then(function () {// 总是会执行});// 上述请求也可以按以下方式完成可选!! 第二个参数和Post不太一样哦
axios.get(/user, {params: {id: 12345}}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);}).then(function () {// 总是会执行}); post/put请求
第一个参数url第二个参数data第三个参数config后两个参数可选
axios.post(/user, { firstName: Fred, lastName: Flintstone}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});四种请求方式的参数 axios.get(url[, config]) axios.delete(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]]) 7.3 跨域问题
自己开发情况下会出现跨域问题解决 cors 后端设置响应头使用多 jsonp 利用script的src属性引用外部资源不受同源策略(协议主机号端口号三者相同)的限制但是只能解决get请求跨域的问题, 前后端配合。使用极少 代理服务器⭐nginxvue-lic。前端和后端之间才有跨域问题后端和后端之间没有同源策略没有跨域问题 http://localhost:8080前端 ---- http://localhost:8080代理服务器 ---- http://localhost:5000真正服务器 // 使用vue-cli的配置src/vue.config.js
/ 第一种,只能配置一个代理,而且如果本服务器已有资源就不能向另一服务器发起请求。
module.exports {devServer: {// 告诉代理服务器将请求转发给谁代理服务器的端口不用我们指定会和我们当前项目保持一致proxy: http://localhost:5000 }
}
// 请求: 发送ajax请求向8080请求而不要向真正服务器5000端口请求了。
axios.get(http://localhost:8080/students).then(response {}) / 第二种可以开启多个代理服务器项目中常用
module.exports {devServer: {proxy: {//请求前缀可自定义/sutong: {target: http://localhost:5000, //url地址被请求服务器的地址ws: true, //是否支持websocket(默认true)//用空代替请求前缀代理往后端服务器的请求去掉 /sutong 前缀pathRewrite:{^/sutong, }, //是否‘说谎’即是不是表明请求来自代理服务器true: 隐瞒(一般设为true,默认true) //控制请求头中的Host(端口号)值,如果为true,则和被请求服务器的端口号相同,反之则请求服务器的Host(端口号)值相同changeOrigin: true},/foo: {target: other_url}}}
}
/*changeOrigin设置为true时服务器收到的请求头中的host为localhost:5000changeOrigin设置为false时服务器收到的请求头中的host为localhost:8080changeOrigin默认值为true
*/// 请求发起axios请求 (不加请求前缀则请求本服务器中的资源)
axios.get(http://localhost:8080/sutong/students).then(reponse {})8. Vue的其他配置
8.1 计算属性
能够将计算结果缓存起来的属性将行为转化成了静态的属性。把data中的属性经过计算再去使用但相对于方法有缓存机制。
div idappinput typetext v-model:valuefirstName/inputinput typetext v-model:valuelastName/input全名方法{{fullName1()}}全名计算属性{{fullName2}}
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
scriptvar vm new Vue({el: #app,data: {firstName: 张,lastName: 三},methods: { // 方法实现但调用几次执行几次没有缓存fullName1() {return this.firstName - this.lastName;}},computed: { // 计算属性最终会出现在vm身上直接读取就行fullName2: {// getter什么使用调用 // 1.初次读取计算属性时 2.所依赖的数据发送变化时 把返回值作为fullName2的值get() {return this.firstName - this.lastName;},// fullName2不允许改的话setter可以没有一般是不做需改的看下面简写set(value) { const arr value.split(-);this.firstName arr[0];this.lastName arr[1];}},fullName2() { // 简写这个函数就当getter用return this.firstName - this.lastName;}}});
/script调用发放每次都要计算都有开销那这个结果是不经常变化的呢此时就可以考将这个结果缓存起来采用计算属性可以很方便的做到这一点计算属性的特性就是将不经常变化的的计算结果进行缓存以节约我们的系统开销 什么使用更新缓存 1.初次读取计算属性时 2. 所依赖的数据发送变化时 8.2 监视属性
监视相比较计算属性能开启异步任务
div idappbuttrn clickflag!flag切换/buttrn
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.js/script
scriptvar vm new Vue({el: #app,data: {flag: true},watch: { flag: { // 监视属性监视falg属性监视计算属性也行immediate: true, // 初始化的时候让handler调用一下。默认falsedeep: true // 深度监视如果flag是个对象,加上这个才会监视flag对象里面属性的变化,默认falsehandler(newVal, oldVal) {console.log(flag被修改了, newVal, oldVal);}}flag(newVal, oldVal) { // 当只需要有一个handler方法的时候可以简写这样函数名就是监视的谁。console.log(flag被修改了, newVal, oldVal);}}});// 或者这样vm.$watch(flag, {handler(newVal, oldVal) {console.log(flag被修改了, newVal, oldVal);}})
/script⭐⭐⭐⭐ 被Vue管理的函数最好写成普通函数这样this才是vm对象 或 组件实例对象所有不被Vue所关闭的函数定时器的回调函数ajax的回调函数Promis的回调函数最好写成箭头函数监听函数没有this就会往外找这样这样this才是vm对象 或 组件实例对象。 8.3 过滤器
对要显示的数据进行特定格式化后再显示适用于一些简单逻辑的处理Vue3已经移除
其实用方法计算属性都能完成
div idrooth3当前时间戳{{time}}/h3h3转换后时间{{time | timeFormater()}}/h3h3转换后时间{{time | timeFormater(YYYY-MM-DD HH:mm:ss)}}/h3
/divscript srchttps://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js/script
script typetext/javascriptVue.config.productionTip false// 全局过滤器Vue.filter(mySlice,function(value){return value.slice(0,11)})new Vue({el: #root,data: {time: 1626750147900,},// 局部过滤器 第一个参数是管道符|前面的值filters: {timeFormater(value, strYYYY年MM月DD日 HH:mm:ss){ // ES6中参数可以有默认值return dayjs(value).format(str)}}})
/script9. 生命周期 生命周期函数里面的this都是vm 或者 组件实例对象 所有的函数看图片 beforeCreate此时无法通过vm访问data中的数据和methods中的方法即数据检测数据代理创建之前 created ⭐此时就可以通过vm访问data中的数据和methods中的方法 beforeMount挂载之前页面呈现未经Vue编译的DOM结构在此时刻自己操作DOM不会生效因为Vue在下一步会替换你的操作 mounted ** ⭐挂载完毕页面呈现经过Vue编译的DOM结构。完成了模板的解析并把初始的真正的DOM放入即把虚拟DOM转化为真实DOM后只调用一次, 至此初始化过程结束。一般再此开启定时器发送请求绑定自定义事件订阅消息…等初始化工作** beforeUpdate 此时数据是新的但页面是旧的 它两个之间会生成新的虚拟DOM和旧DOM比较是否可以复用最终完成页面的渲染Model - View updated此时数据是新的页面也是新的 beforeDestroy ⭐此时vm的datamotheds指令都还可以用马上执行销毁过程但再次操作数据页面不在触发更新了一般进行关闭定时器取消订阅消息解除自定义事件…等收尾工作销毁可以调用vm.$destroy() destroyed已经销毁 10. vue-cli
10.1 简介
vue-cli官方提供的一个脚手架可以快速生成一个vue项目模板。
主要作用统一的目录结果本地调试热部署单元测试集成打包上线类似后端的Maven 先安装node.js环境npm随着nodejs自动安装一路next就行会自动配置Path环境变量node -v/npm -v可查看是否成功。npm就是一个软件包管理工具和Linux下的apt软件管理差不多 安装node.js淘宝镜像加速器cnpm这样后续下载会更快注意安装都要用管理员运行cmd npm install -g cnpm --registryhttps://registry.npm.taobao.org 下载前可以修改一下npm默认的下载路径防止占用C盘空间。-g代表全局安装 安装vue-cli cnpm install vue-cli -g vue-cli最新版输入vue ui即可进入图形化创建项目界面 vue list 可查看可以基于哪些模板创建vue应用程序 10.2 创建项目
vue-cli3版本以上创建项目
打开命令行进入你想在哪创建的目录vue create 项目名选择Vue.js的版本 选完等待即可cd 项目名 进入项目npm run serve 运行项目浏览器访问http://localhost:8080/ 即可看到脚手架帮我们写好的HelloWordctrlc停止
或者进入你要创建到的目录执行vue ui图形化界面创建项目 10.3 项目目录结构
文件目录
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── logo.png
│ │── component: 存放组件
│ │ └── HelloWorld.vue
│ │── App.vue: 汇总所有组件
│ └── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件 (ES6 - ES5)
├── package.json: 应用包配置文件
├── README.md: 应用描述文件,怎么使用
└── package-lock.json: 包版本控制文件可以在项目目录下创建vue.config.js文件修改一些默认的配置。配置项官网配置参考 | Vue CLI (vuejs.org) 11. webpack
11.1 简介
webpack一个现代JavaScript应用程序的静态模块打包器module bundler。当webpack处理应用程序时他会递归的构建一个依赖关系图dependency graph其中包含应用程序需要的每个模块然后将所有的这些模块打包成一个或多个bundle。当下最热的前端资源模块化管理工具和打包工具可以将许多松散耦合的模板按照依赖和规则打包成符合生产环境部署的前端资源。 ⭐ES6规范EcmaScirpt6标准增加了JavaScirpt语言层面的模块体系定义。尽量静态化使编译时就能确定模板依赖关系以及输入输出的。容易进行静态分析但有些原生浏览器还没正常这个。可以使用webpack把ES6规范打包成ES5规范。 import jquery
export dunction doStuff() {}
module localModele {}11.2 安装使用 安装webpack cnpm install webpack -g cnpm install webpack-cli -g webpack -v webpack-cli -v 查看是否成功 配置创建webpack.config.js配置文件有entryoutputmodulepluginsresolvewatch等属性…了解一下 使用webpack
创建一个项目(目录)例如 D:\webpack-study创建modules目录写js代码要有这个主入口main.js工程下创建webpack.config.js 看下面运行webpack命令打包后html页面引入用就行了
// webpack-study/webpack.config.js文件
module.exports {entry: ./modules/main.js, // 主程序入口自动把入口所需要的东西全部打包进来output: { // 打包输出到那filename: ./js/bundle.js}....
};然后运行webpack命令就会生成一个bundle.js打包后的文件打开看一下是个很长的一行
可以使用webpack --watch 一直监听变化js变化就重新打包ctrlc停止 12. vuex
12.1 vuex原理
概念专门在Vue中实现集中式状态数据管理的一个Vue插件对Vue应用中多个组件的共享状态进行集中式的管理读/写也是一种组件间通信的方式且适用于任意组件间通信。
全局事件总线如果很多组件的话实现共享数据读/写比较乱麻烦vuex不属于任何一个组件要共享的数据都放到vuex中读写两个api就能实现
什么时候使用vuex
多个组件依赖同一状态来自不同组件的行为需要变更同一状态
原理图 12.2 基本使用
安装 Vue 2 匹配 Vuex 3 。Vue 3 匹配 Vuex 4 。 我用的vue2安装vuex3版本npm install vuex3 --save 基本使用 初始化数据state配置actionsmutations操作文件store.js 组件中读取vuex中的数据$store.state.数据 组件中修改vuex中的数据$store.dispatch(action中的方法名,数据) 或者$store.commit(mutations中的方法名,数据) 若没有网络请求或其他业务逻辑组件中也可越过actions即不写dispatch直接调用commit
Count.vue相当于Controlleraction相当于Servicemutatisons相当于Dao
src/store/index.js 该文件用于创建Vuex中最为核心的store⭐⭐⭐
import Vue from vue
import Vuex from vuexVue.use(Vuex) // 应用Vuex插件// 准备actions —— 用于响应组件中的动作 可以复用
// 一般把业务逻辑和发送ajax请求写在actions里面
const actions {/* 若没有网络请求或其他业务逻辑组件中也可越过actionsjia(context,value){console.log(actions中的jia被调用了)context.commit(JIA,value)},jian(context,value){console.log(actions中的jian被调用了)context.commit(JIAN,value)}, */jiaOdd(context, value) { // context 相当于精简版的 $storeconsole.log(actions中的jiaOdd被调用了)if (context.state.sum % 2) {context.commit(JIA, value)// context.diapath(demo, value) 如果业务复杂的话还可以继续调diapath(),找actions的方法继续处理}},jiaWait(context, value) {console.log(actions中的jiaWait被调用了)setTimeout(() {context.commit(JIA, value)}, 500)}
}// 准备mutations —— 用于操作数据state
// 名字一般大写便于和actions区分
const mutations {JIA(state, value) {console.log(mutations中的JIA被调用了)state.sum value},JIAN(state, value) {console.log(mutations中的JIAN被调用了)state.sum - value}
}// 准备state —— 用于存储共享数据
const state {sum: 0 // 当前的和
}// 准备getters —— 用于将state中的数据进行加工类似计算属性但这个可以复用可以不写这个配置
const getters {bigSum(state) {return state.sum * 10}
}// 创建并暴露store
export default new Vuex.Store({actions,mutations,state,getters
})src/main.js
import Vue from vue
import App from ./App.vue
import store from ./storeVue.config.productionTip falsenew Vue({store, // vm和所有的组件实例对象有个$store对象了render: h h(App)
}).$mount(#app)Count.vue 单个组件案例使用多个组件操作$store.state都一样操作即可
templatedivh1当前求和为{{ $store.state.sum }}/h1h1当前求和方法十倍为{{ $store.getters.bigSum }}/h1 !-- 注意不是在state里面了--select v-model.numbernoption value11/optionoption value22/optionoption value33/option/selectbutton clickincrement/buttonbutton clickdecrement-/buttonbutton clickincrementOdd当前求和为奇数再加/buttonbutton clickincrementWait等一等再加/button/div
/templatescriptexport default {name:Count,data() {return {n:1, // 用户选择的数字}},methods: {increment(){// this.$store.dispatch(jia,this.n)this.$store.commit(JIA,this.n)},decrement(){// this.$store.dispatch(jian,this.n)this.$store.commit(JIAN,this.n)},incrementOdd(){this.$store.dispatch(jiaOdd,this.n)},incrementWait(){this.$store.dispatch(jiaWait,this.n)},}}
/scriptstyle langcssbutton{margin-left: 5px;}/style12.2 四个map方法 mapState方法用于帮助映射 state 中的数据为计算属性 例如$store.state.sum - sum就不用写这么长了 import {mapState} from vuexcomputed: {// 借助mapState生成计算属性从state中读取数据sum、school、subject对象写法一 // ...是ES6语法把mapState返回的对象每组k-v展开放到computed对应对象中...mapState({sum:sum, school:school, subject:subject}),// 借助mapState生成计算属性sum、school、subject数组写法二...mapState([sum, school, subject])
}mapGetters方法用于帮助映射 getters 中的数据为计算属性 import {mapGetters} from vuexcomputed: {//借助mapGetters生成计算属性bigSum对象写法一...mapGetters({bigSum:bigSum}),//借助mapGetters生成计算属性bigSum数组写法二...mapGetters([bigSum])
}mapMutations方法用于帮助生成与 mutations 对话的方法即$store.commit(xxx)的函数 import {mapMutations} from vuexmethods: {//靠mapActions生成increment方法、decrement方法对象形式...mapMutations({increment:JIA, decrement:JIAN}),//数组形式这样的话使用方法就得button clickJIA(n)/button...mapMutations([JIA,JIAN]),
}// 生成的是这样的。和我们自己写的还是有一点区别的
// 自动生成的话就要传参了button clickincrement(n)/button
methods: {increment(value) {this.$store.commit(JIA, value)}
}mapActions方法用于帮助生成与 actions 对话的方法即$store.dispatch(xxx)的函数 import {mapActions} from vuexmethods:{//靠mapActions生成incrementOdd、incrementWait对象形式...mapActions({incrementOdd:jiaOdd, incrementWait:jiaWait})//数组形式...mapActions([jiaOdd,jiaWait])
}// 生成的样式和上面的一样也要传数据mapActionsmapMutations使用时若需要传递参数在模板中绑定事件时传递好参数否则参数是事件对象。 12.3 模块化命名空间
目的让代码更好维护让多种数据分类更加明确
修改store/index.js文件为了解决不同模块命名冲突的问题将不同模块的namespce: true之后在不同页面中引入getter, actions, mutations时需要加上所属的模块名。
// 求和相关的配置 (可以把这个countAbout写到一个文件中然后暴露)
const countAbout {namespaced: true, // 开启命名空间默认falsestate: {x:1},mutations: { ... },actions: { ... },getters: {bigSum(state) { return state.sum * 10 }}
}// 人员相关的配置
const personAbout {namespaced: true, // 开启命名空间state: { ... },mutations: { ... },actions: { ... }
}// 总配置
const store new Vuex.Store({modules: {countAbout: countAbout, // 简写countAboutpersonAbout: personAbout}
})获取数据
// 自己写
this.$store.state.countAbout.sum
this.$store.commit(countAbout/JIA,this.n)
this.$store.getters[countAbout/bigSum]// 自动生成
computed: {// 第一个参数可以指定分类从countAbout中去后面的state中数据进行映射...mapState(countAbout, [sum, school, subject]), ...mapState(personAbout, [personList])
},
methods: {// 这个也要指定命名空间其他两个map方法一样...mapMutations(countAbout {increment:JIA, decrement:JIAN})
}13. vue-router
13.1 简介
vue-router官方的路由管理器它和 Vue.js 的核心深度集成让构建单页面应用变得易如反掌
专门用来构建SPAsingle page web application单页面应用而且点击页面中的导航链接不会刷新页面只会做页面的局部更新。
功能
嵌套的路由/视图表模块化的、基于组件的路由配置路由参数、查询、通配符基于 Vue.js 过渡系统的视图过渡效果细粒度的导航控制带有自动激活的 CSS class 的链接HTML5 历史模式或 hash 模式在 IE9 中自动降级自定义的滚动条行为 Vue 2 匹配 Vue-Router 3 。Vue 3 匹配 Vue-Router 4 。 安装路由插件当前项目下安装vue-router 进入当前项目目录 我用的vue2先安装vue-router3版本 nmp cnpm install vue-router3 --save-devcdnscript srchttps://unpkg.com/vue-router3.0.0/dist/vue-router.js/script 13.2 简单使用
单HTML路由演示
script srchttps://unpkg.com/vue/dist/vue.js/script
script srchttps://unpkg.com/vue-router/dist/vue-router.js/scriptdiv idapph1Hello App!/h1p!-- 使用router-link组件来导航通过传入to属性指定链接router-link 默认会被渲染成一个 a 标签 --router-link to/fooGo to Foo/router-linkrouter-link to/barGo to Bar/router-link/p!-- 路由出口路由匹配到的组件将渲染在这里 --router-view/router-view
/divscript// 0. 如果使用模块化机制编程导入Vue和VueRouter要调用 Vue.use(VueRouter)// 1. 定义 (路由) 组件。const Foo { template: divfoo/div } // 可以从其他文件 import 进来const Bar { template: divbar/div }// 2. 定义路由// 每个路由应该映射一个组件。 其中component 可以是通过 Vue.extend() 创建的组件构造器或者只是一个组件配置对象。const routes [{ path: /foo, component: Foo },{ path: /bar, component: Bar }]// 3. 创建 router 实例然后传 routes 配置const router new VueRouter({routes // (缩写) 相当于 routes: routes})// 4. 创建和挂载根实例。记得要通过 router 配置参数注入路由从而让整个应用都有路由功能new Vue({router // router: router}).$mount(#app)
/script13.3 单文件注册路由
src/router/index.js配置路由
// 该文件专门用来创建整个应用的路由器
import Vue from vue
import VueRouter from vue-router
import HomeView from ../views/HomeView.vue // 一般组件放到commponents文件夹里路由组件放到views或pages里
import Test from ../views/Test.vue
import Abc from ../views/Abc.vueVue.use(VueRouter) // 应用路由插件const routes [{path: /,name: home, // name可以简化路由跳转如果是二级路由就不用带一级路由的路径了直接写name即可component: HomeView},{path: /test,name: test,component: Test,children: [ // 嵌套路由记得在Test组件中指定Abc组件的渲染位置即使用router-view{path: abc // 注意不用加/了只需要一级路由加component: Abc} ]}{path: *, // 上面匹配不到就去下面指定的redirect: / }
]const router new VueRouter({mode: history, //代表路由模式默认是hash带#号的那种base: process.env.BASE_URL, //应用的基路径,process.env.BASE_URL指从环境进程中根据运行环境获取的api的base_urlroutes //具体的路由配置列表
})export default router // 导出src/main.js
import Vue from vue
import App from ./App.vue
import router from ./router // 默认是: import router from ./router/index.jsVue.config.productionTip falsenew Vue({router, // 安装了路由就有router这个配置项render: h h(App)
}).$mount(#app)实现切换使用router-link标签active-class属性可以设置高亮样式vue帮我们自动切换高亮。
指定展示位使用router-view标签 当切换路由时路由组件是被频繁销毁挂载的可以使用keep-alive标签把要缓存组件包起来让不展示的路由组件保持挂载不被销毁 13.4 路由跳转/传递接受参数
⭐⭐⭐⭐ router-link to/path/router-link 本质是个a标签a标签的属性都可以写。 router-link to/path/router-link !-- 不传递参数可以这么写--!-- 传递数据to字符串写法obj.val是data里面的数据注意有个号--
router-link :to/path/?val${obj.val}/router-link
!-- to的对象写法可以配置name属性,params参数..--
router-link :to{ path: /path, query: {val: obj.val} }/router-linkthis.$router.push() 这种一般是按钮之类的使用这种跳转方式 this.$router.push({ path: /lujing, // name: lujing 也行前提得配置好路由名query: { value: 2 } // 传递参数会用拼接到url中即 /lujing?value2// 传递参数会用/拼接到url中即 /lujing/2 (router路由器中需要配置占位符,即 path: /lujing/:value) // 注意使用params传参不能用path只能用namename: lujing,params: { value: 2 }
})this.$router.replace() 用法和上面的push一样只是history栈中不会有记录一般做404页面 this.$router.go(n) n为1即在浏览器记录中前进一步this.$router.forward() n为 -1即后退一步记录等同于this.$router.back()
this.$router对象是全局路由的实例整个应用的路由器是router构造方法的实例。 有pushreplacego方法
this.$route对象表示当前的路由信息/路由规则包含了当前 URL 解析得到的信息。
// 接受参数
this.$route.query.xxx // 取query参数
this.$route.params.xxx // 取params参数// 怎么模板中减少重复写this.$route.query.xxx 下面只是为了让路由组件更方便的收到参数
// 如果是params传参在路由规则中把props设置为true使用组件中props接受直接写{{xxx}}来获取数据
{name:test,path:test/:id,component: Test,// 第一种写法props值为对象该对象中所有的key-value的组合最终都会通过props传给Test组件// Test组件中页需要props接受, props: [a]就可以直接使用了使用少传递的是死数据// props: {a: 900}// 第二种写法props值为布尔值为true时则把路由收到的所有params参数通过props传给Test组件// Test组件中页需要props接受props: [id]这样使用的时候就不用写this.$route.params.xxx了直接使用id即可// props: true// 第三种写法props值为函数该函数返回的对象中每一组key-value都会通过props传给Test组件// Test组件中页需要props接受props: [id]props($route) {return {id: $route.query.id}}// ES6的解构赋值操作props({query}) {return {id: query.id}}
}//
// this.$route对象属性
fullPath: /“ // 全路径
hash:
matched: [] // 返回一个数组包含当前路由的所有嵌套路径片段的路由记录
meta: {} // 可以附加一些数据
name: null // 路径名name
params: {} // params参数
path: / // 当前的路径path
query: {} // query参数这两个每个组件实例对象都有router每个组件都相同是一个对象。route每个组件都不同存放这自己的路由信息。 13.5 两个钩子
如果组件里面有定时器并且我们写了在beforeDestory()里面进行关闭定时器销毁的时候会关闭定时器。
但如果我们使用keep-alive缓存路由组件的话就不会销毁组件所以定时器也不会关闭一直开着。所以有了下面这两个钩子
路由组件所特有的两个生命周期钩子函数类似mounted - activated beforeDestory - deactivated
activated 激活deactivated 失活
templateulli :style{opacity}欢迎学习vue/lilinews001 input typetext/lilinews002 input typetext/li/ul
/templatescriptexport default {name:News,data(){return{opacity:1}},activated(){console.log(News组件被激活了)this.timer setInterval(() {this.opacity - 0.01if(this.opacity 0) this.opacity 1},16)},deactivated(){console.log(News组件失活了)clearInterval(this.timer)}}
/script13.6 路由守卫
对路由进行权限控制类似拦截跳转
全局全局守卫
全局前置路由守卫全局后置路由守卫
src/router/index.js
import Vue from vue
import VueRouter from vue-router
import Test from ../views/Test.vueVue.use(VueRouter)const routes [{path: /test,name: test,component: Test,meta: { // 一个一个判断path是否需要守卫太麻烦可以标记一个值来判断是否需要守卫里面可以自定义一些属性title: 测试,isAuth: true} }
]const router new VueRouter({mode: history, base: process.env.BASE_URL, routes
}) 暴露之前加入一些守护规则
// 全局前置路由守卫 - 每次路由切换之前被调用(初始化的时候也会被调用一次)
// to是要跳转取路由信息, from的当前路由信息,这两个都是路由信息对象$route。
router.beforEach((to, from, next) { if (to.path /test sessionStorage.getItem(user) ! admin) {alert(你需要admin身份才能访问);} else {next(); // 放行}// 如果自己配置类路由元信息即meta可以这么写if (to.meta.isAuth sessionStorage.getItem(user) ! admin) {alert(你需要admin身份才能访问);} else {next(); }
});// 全局后置路由守卫 - 每次路由切换之后被调用(初始化的时候也会被调用一次)
// 没有next用的不多,可以用来改变一些网页的title
router.aferEach((to, from) {alert(666);
})export default router // 暴露独享路由守卫:注意没有后置路由守卫
import Vue from vue
import VueRouter from vue-router
import Test from ../views/Test.vue Vue.use(VueRouter) const routes [{path: /test,name: test, component: Test,beforeEnter: (to, from, next) { // ...}}
]const router new VueRouter({mode: history, base: process.env.BASE_URL, routes
})export default router // 导出组件内守卫
beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave
templatediv666/div
/templatescriptexport default {name: Test,// 通过路由规则进入当前组件前被调用// 当调用这个方法to永远是当前Test组件路由相关信息beforeRouteEnter(to, from, next) { console.log(beforeRouteEnter);if (to.meta.isAuth sessionStorage.getItem(user) ! admin) {alert(你需要admin身份才能访问);} else {next(); }},beforeRouteUpdate(to, from, next) { // 反复进入这个组件参数变化时console.log(beforeRouteUpdate);next();},// 离开当前组件时被调用即切换走当前组件才调用和全局后置守卫有点区别全局后置守卫是切换成功后立刻调用// 当调用这个方法from永远是当前Test组件路由相关信息beforeRouteLeave(to, from, next) { console.log(beforeRouteLeave);if (confirm(你确定要离开吗)) {next();} else {next(false);}}}
/script13.7 路由两种模式 对于一个url什么是hash值 #及其后面的内容就是hash值 hash值不会包含到http请求中即hash值不会带给服务器
hash模式
地址中永远带着#号不美观若以后将地址通过第三方手机app分享若app校验严格则地址会被标记为不合法兼容性较好
history模式
地址干净美观兼容性相比hash模式略差应用部署上线时需要后端人员支持解决刷新页面服务端404的问题
切换
const router new VueRouter({mode:history,routes:[...]
})export default router14. 组件库
移动端VantCube UIMint UI
PC端Element UIIView UI ElementUI插件安装 npm i element-ui -S i 是 install 的缩写 -S是 --save 的缩写局部安装写入到 dependencies对象。 -D是 --save-dev 的缩写局部安装模块写入到 devDependencies 对象。 总结运行时需要用到的包使用–S否则使用–D 安装SASS加载器 cnpm install sass-loader --save-dev cnpm install node-sass --save-dev src/main.js
import Vue from vue
import App from ./App.vue
import ElementUI from element-ui; // 1. 引入ElementUI组件库
import element-ui/lib/theme-chalk/index.css; // 2. 引入ElementUI全部样式Vue.config.productionTip false
Vue.use(ElementUI) // 3. 使用ElementUI所有组件有点大new Vue({el:#app,render: h h(App),
})src/App.vue
templatedivel-rowel-button iconel-icon-search circle/el-buttonel-button typeprimary iconel-icon-edit circle/el-buttonel-button typesuccess iconel-icon-check circle/el-buttonel-button typeinfo iconel-icon-message circle/el-buttonel-button typewarning iconel-icon-star-off circle/el-buttonel-button typedanger iconel-icon-delete circle/el-button/el-row/div
/templatescriptexport default {name:App,}
/script按需引入⭐⭐ 安装npm install babel-plugin-component -D 修改src/babel.config.js文件 module.exports {presets: [vue/cli-plugin-babel/preset, // 这个是一开始就有的其他是配置的[babel/preset-env, { modules: false }]],plugins: [[component,{ libraryName: element-ui,styleLibraryName: theme-chalk}]]
}src/mian.js import Vue from vue
import App from ./App.vue
import { Button,Row } from element-ui // 按需引入组件样式会根据用的组件自动引入Vue.config.productionTip falseVue.component(Button.name, Button); // Vue.use(Button)
Vue.component(Row.name, Row); // Vue.use(Row)new Vue({el:#app,render: h h(App),
})