wordpress链接去除下划线,优化网站最好的刷排名软件,成都做网站,都什么网站用wordpress前言
爆肝15天#xff0c;本文共4万5千字#xff0c;包含Vue.js理论到实战。知识点全部都能使用ctrlf速查#xff0c;可作为知识点速查笔记使用。
本文完全基于 参考资料#xff1a;尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通加工整理而成#xff0c;包括其代码本文共4万5千字包含Vue.js理论到实战。知识点全部都能使用ctrlf速查可作为知识点速查笔记使用。
本文完全基于 参考资料尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通加工整理而成包括其代码案例资源等。前置知识是学习尚硅谷的视频教程本文配合其教程食用效果更佳。
本文全套资料、案例、源代码、插件已上传至Giteehttps://gitee.com/da-ji/full_stack_developer大家需要可自取
b站直接搜索 vue 第一条结果即是 本文引入的vue版本是2.4.1
!-- 引入Vue --
script srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script目录 前言一、通用概念、前置知识1.1 MVC 和 MVVMMVC 架构偏后端以JavaWeb举例MVVM架构偏前端以Vue举例 1.2 WebPack基本概念 和 Vue-CLI1.3 【面试】虚拟DOM(vitural dom)虚拟DOM 和 v-for 中的key【面试总结】总结key和虚拟DOMreact也有这概念 1.4 vue官方文档和API1.5 双向绑定概念1.6 常用工具和资源网站等bootcdn.cn 收集无数三方库、工具类Vs Code 插件Live ServerVs Code 插件Auto Close TagVs Code 插件Auto Rename Tag其它实用VS插件Vue Devtools 二、Vue 基础笔记1、安装引入Vue.js2、创建Vue对象和Vue插值语法{{ xxx }}【补充】el与data的两种写法Vue实例管理**el的另外写法如下****data的另一种写法函数式如下** 【补充】创建Vue对象时其它可配置属性【methods】可以传各式各样的函数methods 中的 event【重要】methods 调用 data 配置属性computed 计算属性watch 监视属性filters 过滤器template HTML模板 3、Vue指令语法【v-bind】: 绑定html的标签属性【v-model】 双向绑定指令语法和插值语法的区别 4、Object.defineProperty方法常用属性之get和set 5、数据代理数据劫持Vue如何应用数据代理呢 6、事件处理6.1【v-on】绑定单击事件结合前面讲的methods一起学习6.2事件修饰符【JS基础之event】event的常用姿势*event.preventDefault()* 常用事件修饰符共六种键盘事件 7、计算属性computed计算属性要解决的问题计算属性使用案例**计算属性总结**计算属性简写 8、监视属性watch监视属性的其它写法监视属性简写深度监视 总结watch和computed9、v-bind 绑定class、style样式A、绑定classB、绑定style 10、条件渲染v-if、v-else、v-showA、v-show 控制是否显示B、v-ifC、v-else-if 、v-elseD、总结 11、列表渲染相关11.1 v-for11.2 key面试常问11.3 列表过滤模糊搜索watch的实现方案**使用computed 实现上面的功能** 11.5 【重要面试题】Vue检测数据改变的原理引入原因分析解决方案1解决方案2 (使用数组变更方法)使用Vue内置set方法添加data对象没有的属性总结Vue检测数据改变原理 12、Vue收集表单数据单选框特殊绑定技巧多选框特殊绑定技巧下拉框绑定技巧v-model 特殊用法总结全部演示代码 13、Vue过滤器Linux的管道符 |过滤器传参全局过滤器和局部过滤器 14、Vue常用其他内置指令简单v-textv-html 动态渲染HTML带来的问题【补充知识】cookie机制和xss攻击xss攻击 v-cloak n.斗篷 vt.遮盖;掩盖JS阻塞 v-once只动态渲染一次v-pre 15、Vue自定义指令函数式指定完成需求1debug之大写驼峰命名法对象式指定完成需求2全局自定义指令和局部自定义指令总结 16、【面试】vue生命周期函数也称钩子**引入**mounted挂载生命周期函数的this问题其它的生命周期函数钩子间变量传递小技巧局部变量变全局变量路由相关的钩子函数总结 三、Vue 组件化开发1、组件基础概念2、非单文件组件是前置知识**使用Vue.extend创建组件****创建组件三部曲****非单文件组件注意事项debug**组件的简写直接写配置对象即可组件的嵌套VueComponent构造函数 【极其重要、面试】Vue原型链和内置关系Vue 和 vm的关系VueComponent 和 VueComponent实例对象的关系**有了上面的铺垫Vue有一个重要的内置关系** 3. 单文件组件.vue语法概述组件的管理者入口组件 4、Vue-CLI (Command Line Interface)安装CLI、使用CLI创建启动工程分析脚手架目录结构配置文件其他目录其它注意事项引入静态资源文件如bootstrap.css的方法总结文件结构关于vue脚手架配置文件修改关闭vue语法检查/语法检测 5、组件开发其它相关属性5.1 render函数意为渲染5.2 $refs属性概述【重要】ref绑定组件标签**总结** 5.3 props配置项重要可用于父子组件间传输数据自定义组件传入属性props的三种写法(从简单到复杂)总结更多案例父组件利用v-for配合props动态建立多个子组件【重要】儿子如何给父亲传数据呢【重要】兄弟组件之间如何传输数据 5.4 mixin混入局部引入混合全局引入混合 5.5 插件install插件应用场景类似于java的导jar包总结 5.5 scoped CSS样式作用域 6、TODO List 案例 (原始版本)7、浏览器本地存储(localStorage,sessionStorage)**纯JS实现浏览器本地存储功能**localStoragesessionStorage**总结** 8、组件自定义事件$emit绑定好几种写法解绑this.$offnative修饰符绑定原生标签非自定义标签总结补充开发者工具事件视图 9、全局事件总线概念原理如何注册事件总线使用事件总线任意组件传输数据总结 10、消息订阅与发布11、$nextTick12、过渡和动画Animate.css总结 四、Vue ajax1、前置知识和准备2、Vue中axios的基本使用【补充知识】ajax跨域问题使用vue-cli搭建代理服务器方法一简单方法二 综合案例模拟请求 3、vue-resource4、slot插槽最简单的插槽具名插槽作用域插槽总结 五、vuex1、基本概念和应用场景2、[面试】Vuex工作原理3、搭建vuex环境4、实操计算程序使用vuex5、Vuex开发者工具使用6、getters配置项7、mapState、mapGetters、mapActions、mapMutationsmapState、mapGettersmapMutations、mapActions 8、vuex模块化namespace、ajax请求服务器9、总结模块化 六、vue-router 路由1、概念2、安装\引入\基础使用需求引入2.1 router的入口JS和基础引入2.2 router-link、router-view、active-class2.3 目录结构几个注意点 3、嵌套路由children4、路由传参之query参数5、路由传参之params参数6、命名路由name属性7、路由的props配置8、编程式路由导航($router)9、缓存路由组件(标签)10、两个新的生命周期钩子仅在路由有11、路由守卫11.1 全局路由守卫全局前置路由守卫router.beforeEach()全局后置路由守卫router.afterEach() 11.2 独享路由守卫beforeEnter11.3 组件内路由守卫 12、路由器的两种工作模式(history、hash)前端项目上线流程总结 七、Vue UI 组件库Vue适配组件库推荐组件的全部引入和按需引入 八、展望 Vue 3.0**课件位置** 后记 一、通用概念、前置知识
1.1 MVC 和 MVVM
大家一说起MVC 都知道但是和MVVM一对比就搞混了。这里举两个例子搞清楚MVC和 MVVM
MVC 架构偏后端以JavaWeb举例
该架构就是传统JavaWeb项目开发的一般模式比较简单。
下面两张图截取自MVC架构和SSM框架的个人理解详情可直接移步该博客 MVVM架构偏前端以Vue举例
前置知识是你得懂双向绑定本文下面有讲解双向绑定先看双向绑定。
一图说清MVVM图来源自尚硅谷课件本人进行二次加工 在代码中体现上图中的Data Bindings通过VM将M绑定到View 在代码中体现上图中的DOM Listeners通过VM将V绑定到M 执行效果 同时做到了将M绑定到V和V绑定到M就是实现了双向绑定。
VM就是ViewModel其实就是Vue实例本身它负责将View和Model绑定起来
这就是Vue的MVVM体现要理解透彻需要对ViewModel双向绑定Vue实例都有详细的理解。其它前端框架对MVVM有不同的解释但是原理和思想上是一致的。
最后看维基百科对其的定义 1.2 WebPack基本概念 和 Vue-CLI
不需要全部学会WebPack这门技术,只是对其有一个基本认知即可。 它依赖于Node可以使用npm安装
使用npm init 指令构建 package.json 文件 webpack 能够编译打包 js 和 json 文件。 能将 es6 的模块化语法转换成浏览器能识别的语法。 生产环境能压缩HTMLCSSJS代码。 可以打包各种各样的资源样式资源、图片资源、HTML资源提取压缩cssjs语法检查/兼容性处理。
那Vue-CLI是什么呢其实就是Vue官方给我们构建的适用于.vue的打包构建工具
1.3 【面试】虚拟DOM(vitural dom)
虚拟DOM是内存中的数据然后将虚拟DOM变成真实DOM。
原生js不使用虚拟DOM:
Vue使用虚拟DOM方式 虚拟DOM的好处如上图假如用了虚拟dom的技术会将虚拟DOM和真实DOM比较就是上图的diff算法发现001002003是重复的。于是就不会再次渲染001002003. 而是复用它们。
只有004的虚拟DOM是不重复的需要重新渲染。这就提高了展示效率。 虚拟DOM 和 v-for 中的key
v-for 中的 key下文有提到。
虚拟DOM有一个比较算法基于什么比较呢就是基于key
这里直接看对应关系 在进行渲染时会将内存中的老虚拟DOM和新虚拟DOM根据key做比较一旦发现虚拟DOM之间有变化那么只重新渲染变化部分复用未变化部分。所以 key 这个属性很重要。
一旦你的结构中包含输入类DOM会产生错误DOM更新导致界面渲染有问题。
【面试总结】总结key和虚拟DOMreact也有这概念 1.4 vue官方文档和API
https://cn.vuejs.org/
官方推荐的Vue组件包 1.5 双向绑定概念
https://blog.csdn.net/weixin_44757863/article/details/109110132
1.6 常用工具和资源网站等
bootcdn.cn 收集无数三方库、工具类 Vs Code 插件Live Server 该插件真乃神器。内置小型Tomcat以你在VS中打开的文件夹作为根资源运行于一个小型的服务器。
该服务器的默认端口号为5050
如下两张图所示你就是只写了个HTML也会给你跑在localhost:5050这个服务器上 Vs Code 插件Auto Close Tag
Vs Code 插件Auto Rename Tag
其它实用VS插件
JS Quick Console是真神器快速生成console.log() 它不香吗 Vue Devtools
在使用 Vue 时我们推荐在你的浏览器上安装 Vue Devtools。它允许你在一个更友好的界面中审查和调试 Vue 应用。
如何安装
在我的Gitee上的代码已经上传该插件https://gitee.com/da-ji/full_stack_developer大家需要可自取 固定该程序谷歌浏览器 二、Vue 基础笔记
1、安装引入Vue.js
官网链接https://cn.vuejs.org/v2/guide/installation.html
引入Vue之后Vue就作为一个运行在全局的构造函数。我们可以使用这种方式直接创建一个Vue实例点击直接跳转到本文2、创建对象 1.1 原生安装方式在HTML中使用JS标签引入 可以使用绝对路径和相对路径的方式。如果是绝对路径就是https://这种直接引入互联网如果是…/static 这种方式就可以引入自己下载好的vue.js文件。 举例 Vue-Cli
2、创建Vue对象和Vue插值语法{{ xxx }} 下图一图便知 关于上图的补充细节
1、一个vue实例只能绑定一个对应实例。这是一对一关系。多了就解析不了。2、{{}} 插值语法可以写JS表达式。这点和thymeleaf有点类似看下图例子
【补充】el与data的两种写法Vue实例管理
el的另外写法如下 原理是因为调用了原型链上的 $mount属性
至于什么是原型链下面会讲解。现在只需要记住可以使用这种方法来绑定容器即可。 data的另一种写法函数式如下
组件式开发全部都是函数式。该函数必须返回一个对象。
注意这个函数只能写成普通函数。如果写成箭头函数箭头函数的this是window普通函数的this就是Vue实现对象
ES语法小课堂
普通函数的this指向是调用它的那个对象而箭头函数没有this如果强制它this由于无人调用最终指向的就是window。 ES规范中如果想在对象中写函数还可以这样简写和上图完全就是一个东西只不过简写了而已 就如上图那个data()一样今后我们可以看到由很多由Vue管理的函数Vue对象会调用它。凡是由Vue管理的函数都不能写成箭头函数给老老实实的写成普通函数
【补充】创建Vue对象时其它可配置属性
刚刚只介绍了el和data这里陆续介绍其他的。
【methods】可以传各式各样的函数
但是这个函数仍然受到Vue管理所以不能写成箭头函数只能写成普通函数。
methods是个对象里面可以传入各式各样的函数。
传入的函数要符合JS对象的某个属性是函数的语法规则。可以自行搜索JS对象中如何让其某属性变成一个函数
举例 methods 中的 event
event在不使用Vue时可以通过windows.event调用
在Vue中如果你不传任何参数methods中的函数可以自动获取到event Vue中如果你想传一个实参event对象event为浏览器内置的全局对象不能直接写event而是应该写$event
如果你想用event有一个【实参】占位符 $event可以传入event给形参中
【重要】methods 调用 data 配置属性
使用this即可。 红色箭头是使用this获取到data的值但是高明的地方在于蓝色箭头因为蓝色箭头使用v-model对data的属性进行了双向绑定那么input框一旦改变那么就会引起data改变data改变从而引起methods里的自定义函数的返回值改变
computed 计算属性
点击直接页内跳转到计算属性这一章
watch 监视属性
点击直接页内跳转到监视属性这一章
filters 过滤器
点击直接页内跳转到过滤器这一章
template HTML模板
下图是最简单的用法
不过一般不这么用更多用法详见Vue组件开发一章。
3、Vue指令语法
前面在2里面讲了Vue插值语法 {{}},这里讲指令语法。 这一块和thymeleaf更像了直接在标签上绑定就行。
【v-bind】: 绑定html的标签属性
v-bind可以直接简写为 : (一个冒号) v-bind: 后面的双引号和{{}}插值语法一样可以写JS表达式。 和thymeleaf一样v-bind: 可以绑定任何标签。 【v-model】 双向绑定
https://blog.csdn.net/weixin_44757863/article/details/109110132
补充两个注意事项
1、如下图 2、v-model:value的简写就是 v-model。原因很简单因为v-model只能应用在表单类输入类元素上。
例 指令语法和插值语法的区别
插值语法用于标签体例
pHello{{name}}/p而指令语法则是直接绑在标签的自定义属性上例
a v-bind:hrefdefineUrl v-bind:xxxxhello超链接/a4、Object.defineProperty方法
更高级的给对象添加属性方式。比原来的person.age这种方法高级的多可以配置很多详细信息。
用法如下图更多详细的配置对象属性可以自行百度。 如果设置了不可以枚举【默认就是不可枚举】那么就不能用for-each循环遍历对象属性了。 常用属性之enumerable布尔类型默认值是false。如果想让该字段可枚举就要显式设置为true。 常用属性之configurable布尔类型默认值是false。控制字段是否可以被删除 常用属性之writable布尔类型默认值是false。控制字段是否可以被修改 常用属性之value就是赋值赋字段一个值。
常用属性之get和set
get和set这两个属性特别重要所以单独拿出一节来讲解。
来看下面一个场景
let number 18let person {name: 大吉,sex: 男,age: number}console.log(person.age) //输出18number 22 //将number这个变量修改为22console.log(person.age) //输出仍然是18而不是22
如果我们想让第二个console.log输出的是22呢应该怎么操作
这里就引入了我们强大的get和set功能了
接上图例子使用get将输出修改为22
let number 18let person {name: 大吉,sex: 男,age: number}console.log(person.age) //输出18Object.defineProperty(person, age, {get() {console.log(有人读取了age属性)return number; //return值很重要}})number 22 //将number这个变量修改为22输出的是22。只要有人读取age属性就会调用get方法get方法return的值就是number这个变量console.log(person.age) //22执行效果如图所示 所以我们通过get实现了只要有人读取age属性就可以执行get这个方法至于get这个方法你里面想塞什么都可以。反正只要有人读取age这个属性就执行get。
下面再看set方法
let number 18let person {name: 大吉,sex: 男,age: number}console.log(number的值是 number) //18Object.defineProperty(person, age, {//只要有人修改age属性//就会调用set方法且会收到修改age属性的具体值set(value) {console.log(有人修改了age属性age value)//神奇的操作来了我们让number这个变量修改number value; }})person.age 22 //修改age属性从而调用set方法//非常神奇我们明明修改了age却能对number做修改console.log(number的值是 number) //22执行效果图 总结通过get和set使得操作对象更加灵活了
为什么要学这个Object.defineProperty方法呢是为了下一节数据代理做准备
5、数据代理数据劫持
概念数据代理就是通过一个对象对另一个对象中属性的操作读/写
直接看下图 上图中如果有人动了obj2相当于通过obj2动了obj。 这就是最简单的数据代理实例
Vue如何应用数据代理呢 通过数据代理我们本应该操作vm._data.属性现在我们直接操作vm.属性即可。
6、事件处理
6.1【v-on】绑定单击事件结合前面讲的methods一起学习
其简写是 符号
举例(下面两种方式等价。)
button v-on:clickfunc1按钮/button
button clickfunc1按钮/button
如果你想传参(当然你的func1的定义处也需要定义形参才可以)
button v-on:clickfunc1(a,b,c,d)按钮/button如何将func1和func2被Vue管理呢移步前文中的methods一查便知。
6.2事件修饰符
对事件进行操作前置知识是你得知道JS中的event。
【JS基础之event】
https://blog.csdn.net/lhjuejiang/article/details/79455801
event是一个内置的全局对象我们看看里面有什么
button onclickfunc1(event)按钮/buttonfunction func1(event) {console.log(我是个函数)console.log(event.target)}上面的代码调用了func1并且传入了全局的event下面来看event的属性 event的常用姿势
event.preventDefault()
它可以阻止默认事件的发生。比如a标签其默认事件是跳转。如果我们想阻止单击超链接的跳转可以这么玩儿
a hrefhttps://www.baidu.com onclickfunc0(event)超链接/afunction func0(event) {event.preventDefault()
}此时打开控制台 event的 defaultPrevent属性默认为false的现在是true了。现在单击超链接将不会跳转。
回到事件修饰符中来如果我们想在Vue中实现上述操作需要怎么做呢事件修饰符马上登场
div idroota hrefhttps://www.baidu.com click.preventfunc00(event)被Vue管理超链接/a
/div
scriptnew Vue({el: #root,data: {},methods: {func00(event) {console.log(vue阻止页面跳转)}}})
/script
上面一坨代码和event.preventDefault() 是一样的效果。
click.prevent就是一个事件修饰符。
常用事件修饰符共六种
prevent、stop、once、capture、self、passive
stop可以阻止事件冒泡到它的上层 onceonce如果作用于按钮或者超链接那么超链接只有第一次点击的时候 会跳转除此之外该超链接将不会跳转。
键盘事件
以 keyup.xxx 当键盘弹起 事件 为例
有keyup当然就有keydown当键盘按下立刻触发某事件。 上面的keyup.esc就是当esc键弹起就触发showInfo这个自定义函数该函数必须受Vue管理即放在methods中
其它常用的按键别名 上图的2 解释假如你想绑定CapsLock你应该这样写keyup.caps-lockxxxFunction即转为小写且短横线命名。
【DEBUG】似乎这里的事件修饰符绑定的函数不可以写 xxxFunction() 后面的小括号。否则会报错。必须把小括号去掉才可以。
7、计算属性computed 计算属性要解决的问题
计算属性要解决的问题是插值语法{{}} 中越来越长的JS表达式不利于阅读和组件化的问题。
来看案例 计算属性使用案例
计算属性和data联动同样可以用this。看下例 上图input框框中的 firstName、lastName 和下图 data中的 firstName、lastName 是双向绑定关系。
input框变化data也会变。如果此时有人调用 计算属性中的fullName那么fullName自然会变化。
计算属性中get还有一个属性只要get里面绑定的data有变化也相当于调用了一次vm中的 get() 所以只要data里面的firstName和lastName变了那么fullName即被调用。 执行效果图 顺便一提计算属性的属性也有set和Object.defineProperty的set用法原理一样如下图所示 计算属性总结
为什么叫计算属性它是根据 data中已经有的属性计算得出来的复杂属性。 计算属性简写
当你的计算属性只有人读没有人修改也就是只有get没有set那么计算属性可以简写为 上图等价于下面的代码其实就是简写了getcomputed是一个对象对象的 fullName 字段是一个函数而已 computed: {fullName: {get() {console.log(get被调用了)return this.firstName - this.lastName}}}8、监视属性watch 概念作用监视属性仍然是监视 data 的属性变化也可以监视计算属性。
监视属性的传值是一个配置对象。
当data里面的某字段发生变化就调用handler函数handler函数里面有两个入参分别是newValue、oldValue顾名思义代表修改前和修改后。如下图所示 如果被监视结构是多级的
data:{numbers:{a:1,b:1}
}
那么应该这样配置 watch: {numbers.a: { //这样配置多级结构handler() {console.log(a被改变了)}}}监视属性的其它写法
调用vm的$watch方法 这种写法可以简写。但是简写的前提是watch的配置项只有handler一个参数不能有什么deep啊immediate之类的。
简写办法 监视属性简写
简写的前提是watch的配置项只有handler一个参数
immediate :true 初始化时让handler调用一下。 什么immediate 啊deep啊都不能写才能用这个缩写。 深度监视
深度监视是默认关闭的。
场景如下
如果被监视结构是多级的
data:{numbers:{a:1,b:1}
}
如果你想监测 numbers.a 的变化上文已经讲过如何监视了。这里不做讲解。但是如果a变化了那么numbers应该是也变化的。但是Vue却不认为numbers变化了此时你再监视numbers假如numbers.a被修改那么Vue不认为numbers被修改。
如下所示 watch: {numbers: {handler() {//就算numbers.a变了下一句也不会执行console.log(numbers被改变了)}}}
解决方案打开深度监视 watch: {numbers: {handler() {deep:true, //开启深度监视//numbers.a变了下一句会执行console.log(numbers被改变了)}}}
深度监视总结
总结watch和computed
如果是需要异步请使用watch。因为computed依赖于get和返回值。
所有被Vue管理的函数请写成普通函数。因为你需要让this的指向为vm
所有不被vue管理的函数比如各种回调函数定时器的回调函数ajax的回调函数promise的回调函数最好写成箭头函数。这样this的指向才能指向它们本来应该指向的。如果你这里写成普通函数就会造成调用失败因为你的this指向了vm
因此到底写普通函数还是写箭头函数需要判断this指谁。如果需要this指向vm必须写普通函数否则如果需要this指向其它调用者请使用箭头函数。 9、v-bind 绑定class、style样式
A、绑定class
其实就是 v-bind 绑定一个class
可以如下图一样写成数组写成字段也可以写成对象。
三种不同的写法 先演示写成字段和 写成数组 最后演示写成对象通过true和false决定对象内属性生效与否 B、绑定style
常用对象写法
如下图所示对象写法里面的属性字段不能瞎写需要下划线转驼峰的写法 除了对象写法还有数组写法用的不多 10、条件渲染v-if、v-else、v-show
A、v-show 控制是否显示
v-show只能接收布尔类型既可以直接写truefalse也可以写true和false类型的表达式
h1 v-show1 3大吉/h1
这样写的话h1这个标签就会隐藏因为里面的值是false
也可以写data里面的类型为 true/false 的属性 v-show隐藏掉的元素只是样式隐藏不可见而已但是元素还在invisible true。但是下面的v-if却是直接干掉。
B、v-if
和v-show用法一致填写一个布尔类型的表达式。
但是和show不同元素被直接干掉了而不是样式隐藏。
C、v-else-if 、v-else
一图便知 如果在 条件判断之间有元素将其打断 那么后面就不生效了。
D、总结 11、列表渲染相关
11.1 v-for
最简单的实例 形参还可以是两个参数如下图所示
第二个参数固定就是索引
v-for还可以遍历对象这里的第2个参数就不是索引了两个参数分别是 value 和 key 11.2 key面试常问
在使用for循环的时候不管是vue还是react都应该给每一个遍历生成的html元素取一个名字。这就是key
如果你不写key 那么vue会自动将index作为key。但是非常建议你手动指定一个key。一般情况下不能不写key。index是什么点我跳转
举例 key还可以填入index 如果你不写key那么有可能会出现渲染错误的问题。为什么会出现这个问题呢因为key和虚拟dom有关。
key的原理和虚拟DOM相关点我页内跳转虚拟dom和key的对应关系。
最后看官方定义
11.3 列表过滤模糊搜索
场景 watch的实现方案 下面代码难点如下
immediate :true 初始化时让handler调用一下。JS基础Array filter使用JS基础indexOf使用 上述代码大概原理就是
1、使用v-model让输入框中元素绑定到data的 keyWord中2、使用watch监控keyWord一旦keyWord改变了立刻执行过滤关键字3、一旦keyWord改变了过滤关键字之后会返回一个全新的数组将该数组赋值给data的 filPerson中4、filPerson负责被前端的v-for遍历显示过滤后模糊查询后的结果
使用computed 实现上面的功能 上述代码大概原理就是 1、使用v-model让输入框中元素绑定到data的 keyWord中 2、利用filter输入框变化引起keyword变化引起persons变化 3、建立计算属性filPersons当persons有变化那么就重新计算一次filPersons。 4、filPerson负责被前端的v-for遍历显示过滤后模糊查询后的结果
11.5 【重要面试题】Vue检测数据改变的原理
本章Demo引入的vue版本是2.4.1如果版本太新会报错
!-- 引入Vue --
script srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script引入
需求点击按钮只修改马冬梅的信息 代码编写 在上图代码中方式1生效方式2不生效。这是为什么Vue不承认方式2吗
原因分析
直接赋值的方式不被vue认为是响应式的。
解决方案1
不谋求修改数组单个元素而是替换整个数组。类似这样
this.persons {
{id:001, name:马老师,age:50,sex:男}, //替换该项{id:002, name:周冬雨,age:33,sex:男},
{id:003, name:周杰伦,age:33,sex:男},
{id:004, name:周冬雨,age:33,sex:男}
}
替换数组 这里可以用filter、concat、slice实现 解决方案2 (使用数组变更方法)
this.persons.uns
hift({ name: jack, age: 70 })
对Array进行操作而且想让Array仍旧是响应式必须使用Vue给我们内置的七个方法 原生JS这么多操作数组的方法为什么只有这7个被Vue封装呢因为这7个元素会改变原生数组。判断依据就是该方法会不会改变原生数组 为什么上面的解决方案生效呢因为Vue帮我们封装了数组的常用方法
push、pop、shift、unshift、splice、sort、reverse vm的push 和 Array的push方法不一样vue帮我们做了两件事
1、调用了原生数组的push2、触发视图viewmodel的更新 使用这种方式增改Array元素可以使用 等于号对其中的对象赋值其赋值仍旧是响应式的 不用非得使用vue内置set方法赋值
使用Vue内置set方法添加data对象没有的属性
假如你的dom想添加一个vue的data没有的属性呢注意是添加没有的而不是修改现有的。
添加之前没有的根据上面的Vue检测数据改变的原理, 我们必须使用内置的set方法才能添加一个响应式的data属性。
直接看案例点击按钮给vm添加data属性并展示 使用Vue.set 可以实现。
绝对不能使用 this.student.sex “男” 这种方式 判断是否真的是响应式依据就是该属性有没有 getter 和 setter下图就是响应式的 总结Vue检测数据改变原理 本章全部演示代码如下所示
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/headbodydiv idrootbutton clickstudent.age年龄1岁/button br /button clickaddSex添加性别属性/button br /button clickstudent.sex 未知 修改性别属性/button br /button clickaddFriend在列表首位添加一个朋友/button br /button clickupdateFirstFriendName修改第一个朋友的名字为张三/button br /button clickaddHobby添加一个爱好/button br /button clickupdFirstHobby修改第一个爱好为开车/button br /h3姓名{{student.name}}/h3h3年龄{{student.age}}/h3!-- 只有vm._data有性别才会显示这个标签 --h3 v-showstudent.sex性别{{student.sex}}/h3ulli v-for(h,index) in student.hobby :keyindex{{h}}/li/ulh3朋友们/h3ulli v-for(f,index) in student.friends :keyindex{{f.name}}--{{f.age}}/li/ul/div/body!-- 引入Vue --
script srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script
script//创建Vue实例const vm new Vue({el: #root,data: {student: {name: 大吉,age: 18,hobby: [抽烟, 喝酒, 烫头],friends: [{ name: friends1, age: 35 },{ name: friends2, age: 36 }]}},methods: {addSex() {debugger;//Vue.set(this.student, sex, 男) //方式1必须这样做才能响应式this.$set(this.student, sex, 男) //方式2必须这样做才能响应式},addFriend() {this.student.friends.unshift({ name: jack, age: 70 }) //必须这样做才能响应式},updateFirstFriendName() {this.student.friends[0].name 张三},addHobby() {this.student.hobby.push(学习)},updFirstHobby() {this.student.hobby.splice(0, 1, 开车)}}});/script/html12、Vue收集表单数据
单选框特殊绑定技巧
如果input type 是一个radio复选框这里较为特殊
!-- v-model 只能收集value值 --男input typeradio v-modelsex valuemale namesex女input typeradio v-modelsex valuemale namesex br /br /需要v-model绑定data属性的同时指定value值value可相等 多选框特殊绑定技巧
如果input type 是一个checkbox复选框这里较为特殊 必须保证绑定data数据是数组同时必须指定不相同的value
为啥是数组呢因为这是多选框要多选啊肯定是数组! 效果如图为什么必须用数组接收 下拉框绑定技巧
如果input type 是一个select 和option 下拉框
因为 option里面有value属性所以只需要绑定select即可(option只需要写入value该value会和vm互动) select v-modelcityoption请选择校区/optionoption valuebeijing北京/optionoption valueshanghai上海/optionoption valueshenzhen深圳/optionoption valuewuhan武汉/option/selectv-model 特殊用法
去掉前后空格只需要 v-model.trim即可 总结 全部演示代码
效果 代码
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
div idrootform账号input typetext v-modelname br /br /密码input typetext v-modelpassword br /br /性别!-- v-model 只能收集value值 --男input typeradio v-modelsex valuemale namesex女input typeradio v-modelsex valuefemale namesex br /br /爱好学习input typecheckbox v-modelhobby valuestudy打游戏input typecheckbox v-modelhobby valuegame吃饭input typecheckbox v-modelhobby valueeatbr /br /校区select v-modelcityoption请选择校区/optionoption valuebeijing北京/optionoption valueshanghai上海/optionoption valueshenzhen深圳/optionoption valuewuhan武汉/option/selectbr /br /其他信息textarea/textarea br /br /input typecheckbox v-modelagree阅读并接受a hrefwww.baidu.com《用户协议》/abutton提交/button/form
/divbody/bodyscript srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script
scriptconst vm new Vue({el: #root,data: {name: ,password: ,sex: male, //默认是男hobby: [],city: beijing,other: ,agree: }});/script/html13、Vue过滤器Linux的管道符 |
这章能实现的功能使用method和computed完全能实现只不过过滤器能够进一步的简化而已。 直接看例子 过滤器传参
如果只传一个参数那么默认肯定就是管道符前面的元素很好理解这和linux管道符是一样的
但是过滤器也可以传入多个参数
其中第一个参数一定是管道符前面的元素只有第二个参数才是自定义的参数 全局过滤器和局部过滤器
之前写的是局部过滤器只有一个vm能用。
下图展示了全局过滤器 14、Vue常用其他内置指令简单
之前学过的指令 v-text v-html 动态渲染HTML带来的问题
比起v-text更高级的地方可以解析html标签 效果如下 但是这种方法是有风险的 在网站上动态渲染HTML非常危险容易导致XSS攻击比如窃取cookie
【补充知识】cookie机制和xss攻击
cookie机制 跨浏览器读取Cookie是不生效的 里面包含了我们的用户信息权限校验等等各种信息
这也就解释了使用postman调用某些网站接口调用不通必须得有cookie才能调用通过。
而cookie包含了一系列权限校验信息。
查看cookie 如下图所示 也就是说假如有人得知了我们的某网站的cookie全部信息并且将这些cookie设置到该人的浏览器上那么该人不用登录就可以登陆到你的账号上了
xss攻击
XSS的攻击方式就是想办法“教唆”用户的浏览器去执行一些这个网页中原本不存在的前端代码。
比如使用 document.cookie命令窃取用户的cookie信息
v-cloak n.斗篷 vt.遮盖;掩盖
JS阻塞
如下图所示如果JS代码引入在body之外
一旦链接阻塞上图会让整个浏览器阻塞5秒等JS全部加载出来才能渲染界面
但是如果JS像下图一样引入 v-cloak作用是配合css使用。在JS阻塞(vue.js加载不出来)之前v-cloak标签会被自动移除。也就是说只要vue.js加载出来那么v-cloak标签就不存在。 上图中如果遇到JS阻塞h2会被css控制而不显示。一旦vue.js被加载出来v-clock将不存在。从而使CSS代码失效h2会显示出来。 v-once只动态渲染一次 v-pre
vue不会解析带有v-pre的节点。这个节点不能乱用只有优化性能时候用得到
15、Vue自定义指令
需求 函数式指定完成需求1 debug之大写驼峰命名法 所以在官方风格指南中如果遇到长单词别用驼峰了用短横线。
对象式指定完成需求2
对象式指定比较高级它能完成所有函数式指定的功能并且还能自定义调用时机
对象式指定必须写Vue给我们规定的函数名否则不予解析。常用的函数名有三个bind、inserted、update 上图的三个函数bind、inserted、update其形参都可以接收到【函数式指定】说的element和binding这两个形参。 bind、inserted、update 三种方法就是vue解析的三种不同的时机。在vue解析的不同时刻每一个时间点vue会帮我们调用这三种不同的函数之一。
全局自定义指令和局部自定义指令
和前面的全局过滤器和局部过滤器规范完全一致
函数式指定全局 对象式指定全局 区别就是第二个参数到底是传对象还是传函数而已。
总结 16、【面试】vue生命周期函数也称钩子
react也有类似的钩子概念和vue的概念类似
引入
需求做一个这个效果 方式一不推荐
下面这种方法依赖于形参vm。并没有集成在Vue初始化里面。
bodydiv idrooth2 :stylestyleObj欢迎学习vue/h2/div
/bodyscript srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script
scriptconst vm new Vue({el: #root,data: {styleObj: {//opacity 是style的样式负责控制透明度opacity: 0.5,color: orange}},});//方式1通过操作vm的样式不推荐setInterval(() {vm.styleObj.opacity - 0.01if (vm.styleObj.opacity 0) vm.styleObj.opacity 1}, 16);
/script
方式二破坏了原来需求需要点一下才能触发 上面两种方法均无法完成需求下面使用mounted将需求完成
mounted挂载
概念vue完成模板的解析并把初始的真实DOM元素放入页面后挂载完毕会调用mounted。mounted只会被调用一次。
使用mounted完成上述需求
bodydiv idrooth2 :stylestyleObj欢迎学习vue/h2/div
/bodyscript srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script
scriptconst vm new Vue({el: #root,data: {styleObj: {//opacity 是style的样式负责控制透明度opacity: 0.5,color: orange}},methods: {},mounted() {console.log(vue模板被解析完成会调用我一次)setInterval(() {this.styleObj.opacity - 0.01if (this.styleObj.opacity 0) this.styleObj.opacity 1}, 16);},});/script完美实现
通过观察上述mounted用法可以知道mounted其实就是一个普通的函数。这个函数的调用时机其实就是DOM加载完毕后且只会被调用一次。
mounted就是一个vue生命周期函数。 生命周期函数的this问题
生命周期函数的this已经被维护好就是指vm。所以里面如果需要用到的函数形参会传入箭头函数比如上面的setInterval第一个参数就是箭头函数就应该写箭头函数该箭头函数里面的this就会找到vm本身
其它的生命周期函数
来源于官网的生命周期图示 尚硅谷更进一步的解释 上图中红色框框的都是生命周期函数可以像mounted那样去调用
vm.$destroy() 用于完全销毁一个vue实例。
钩子间变量传递小技巧局部变量变全局变量
利用钩子函数的this就是指vm本身的特性可以将局部变量挂在vm上这样钩子间局部变量就成了共享的全局变量了
例子 解决方案将id这个变量挂在vm上它就成了全局的了 路由相关的钩子函数
前置知识是路由移步路由章节。
总结
其实能够得最多的两个钩子就是mounted和beforeDestroy两个 三、Vue 组件化开发
1、组件基础概念
传统方式开发的痛点和引入组件的好处 vm对象和组件的关系
首先只有一个vm对象。剩下的都是组件组件又称小vm具有部分vm功能 2、非单文件组件是前置知识
先学这个。
使用Vue.extend创建组件
里面传入的配置对象和new Vue的时候传入的配置项几乎一致但是有下面几点需要注意 一定不要写el配置项。因为组件的定义决定了组件作为模块化开发的一块砖哪里需要哪里搬。所以组件不需要对任何父组件负责只对vm本身负责。data必需写成函数式否则报错。原因和上面一样组件如果被多次引用写成函数可以保证局部的封装性。使用template对html进行渲染, 注意template内的html只能有一个根元素。组件分为局部组件和全局组件。 注册全局组件只需要 Vue.component(组件名,要注册的组件位置)即可。通常这两个参数是一样的
创建组件三部曲 代码如下
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/headbodydiv idroot!-- 第三步在root中编写组件标签 --xuexiao/xuexiaoxuesheng/xuesheng/div
/body
script srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script
script//第一步创建组件1const student Vue.extend({//使用template对html抽出来组件化。注意template内的html只能有一个根元素。template: divh2姓名{{name}}/h2h2年龄{{age}}/h2/div,data() {return {name: 大吉,age: 18}},})//第一步创建组件2const school Vue.extend({template: divh2地址{{address}}/h2/div,data() {return {address: 北京}},})const vm new Vue({el: #root,//第二步vm注册组件局部注册components: {xuexiao: school,xuesheng: student}});/script/html效果图如下 非单文件组件注意事项debug
组件名的大小写问题会报错。要注意。组件名和HTML元素不能重名可以使用name字段指定组件在开发者工具中的名字仅能骗过开发者工具而已
组件的简写直接写配置对象即可
下面两种写法等价 组件的嵌套
如下图组件间有嵌套关系。 任务目标
在Vue开发者工具中实现下图嵌套结构 【注】标准化开发中我们会建立一个组件该组件只负责管理组件不负责渲染数据。也就是说这个组件承担管理者角色只对vm(root)负责。在上图中app组件就承担了上述角色。 代码实现
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/headbodydiv idroot!-- 什么都不用写 --/div
/body
script srchttps://cdn.jsdelivr.net/npm/vue2.4.1/dist/vue.js/script
script//student写在上面school在下。防止school引用不到儿子const student Vue.extend({template: divh2姓名{{name}}/h2h2年龄{{age}}/h2/div,data() {return {name: 大吉,age: 18}},})//school和student是父子关系const school Vue.extend({template: divh2地址{{address}}/h2student/student /div,data() {return {address: 北京}},components: { //套娃将儿子student引入进来student}})//hello和school是平级关系const hello Vue.extend({template: divh2{{hello}}/h2/div,data() {return {hello: hello}},})//组件的管理者app只对vm负责的组件一人之下万人之上//该组件不负责任何渲染。const app Vue.extend({/* 下面千万别忘了用div包裹school和hello因为只能有一个root */template: divschool/school hello/hello /div ,components: {school,hello}})const vm new Vue({el: #root,template: app/app,//第二步vm注册组件局部注册components: {app}});/script/html
VueComponent构造函数
组件是什么如果我们输出一个组件会怎样 发现它其实是一个函数准确的说他是一个构造函数。 特别注意每次调用Vue.extend返回的都是一个全新的ViewComponentViewComponent实例对象以后简称vcvc中的this指向vc本身vm中的this指向vm本身 【极其重要、面试】Vue原型链和内置关系
Vue 和 vm的关系
Vue是一个函数vm是其new出来的实例对象
因此:vm.__proto__ Vue.prototype
VueComponent 和 VueComponent实例对象的关系
VueComponent 是一个函数VueComponent实例对象是一个对象
当渲染VueComponent时VueComponent实例对象就被自动new出来了
因此VueComponent实例对象.___proto___ VueComponent.prototype.__proto__
有了上面的铺垫Vue有一个重要的内置关系
VueComponent.prototype.__proto__ Vue.prototype所以VueComponent实例对象.__proto__ VueComponent.prototype.__proto__ vm.__proto__ Vue.prototype有这个内置关系的原因是 让VueComponent实例对象可以访问到Vue原型的属性和方法。
【补充】JS原型相关知识 注意显式原型属性只有函数有对象没有对象只有隐式原型属性
所以函数.prototype 是一个对象。它再往上追溯原型链就只能找__proto___了
因此VueComponent.prototype.__proto__ Vue.prototype对象对象这个等式成立。
那么 Vue.prototype也就是vm.__proto__身上有什么呢 有生命周期函数mount, watch 等等 继续走 :
函数实例的原型属性函数对象.__proto___,永远指向自己缔造者函数的原型对象(函数.prototype)
原型链的尽头是ObjectObject实例的原型属性指向null。这就是原型链的尽头了
如下图的绿色箭头则可反映上述原型链关系 最后一张图 Vue这样做的目的让VueComponent可以访问到Vue原型的属性和方法。
3. 单文件组件.vue
前置知识是非单文件组件必需学那一章。否则看不懂. 语法概述 使用默认暴露方式将组件暴露出去ES6模块化知识
默认暴露
上图代码可以直接简写成 【注】如上图所示name字段必须和文件名一致。这是约定俗成的规矩.
组件的管理者入口组件
还记得上文讲单文件组件时提到的app组件吗 在Vue模块化开发中的确有这么个组件
app组件写法如下 app组件已经一人之下万人之上了。所以这就引出了入口组件也就是vm
在vue模块化开发中使用main.js作为入口组件它负责引入App.vue(管理者组件) 在html页面中只需要准备好一个id为root的div然后引入main.js 即可。
4、Vue-CLI (Command Line Interface)
vue脚手架是vue官方提供的标准化开发工具开发平台
其实就是一个官方版本的webpack
官方文档https://cli.vuejs.org/zh/
安装CLI、使用CLI创建启动工程
NODEJS更换淘宝镜像源
npm config set registry https://registry.npm.taobao.org
执行命令安装CLI
npm install -g vue/cli
如何用该脚手架创建工程 cd到你想创建的目录 执行命令vue create 工程名 手动选择创建Vue2还是Vue3版本这里选择Vue2 cd到创建好的工程中执行命令npm rum serve 如上图所示一个内置的Tomcat就起来了直接访问localhost:8080即可get到你的Vue项目。 神奇的是下面这串地址Network如果你同事处在一个局域网环境下输入了也可以get到你的Vue项目
分析脚手架目录结构
配置文件 package.json node的知识点符合NPM配置规范的会有这个文件。 web-pack里面的短命令也在其中。 babel.config.js babel的配置文件涉及到ES6转换ES5 package-lock.json
包版本控制文件。包括用到的插件资源文件等等。
作用是以最快速度安装到指定版本版本锁定功能在这个文件中锁着。
其他目录 main.js 就是上文说的入口组件。当 npm run serve被执行了就会执行main.js 其它注意事项
index.html的路径问题
内置了BASE_url实际上指的就是./public 目录 引入静态资源文件如bootstrap.css的方法 总结文件结构 关于vue脚手架配置文件修改 关闭vue语法检查/语法检测
在vue.config.js中配置
lintOnSave:false 5、组件开发其它相关属性
5.1 render函数意为渲染
render 提供提交渲染
render函数的原生写法 通过原生写法我们可以发现它其实就等同于之前学非单文件组件中的创建vm样例中的template和components的功能。
但是我们一般不这样写render而是使用简略写法 其实就是帮我们创建模板加载组件。
为什么要用render因为vue-cli默认加载的是运行版本的Vue它不认识 template和components这两个标签所以只能用render。 5.2 $refs属性
概述
在Vue中如果你想拿Dom元素用下图的方法就不优雅了 Vue解决的办法也很简单设置一个$refs属性该属性绑定在VueComponent实例对象(vc)上:
如果绑定在原生HTML标签上本质就是给其加了个id属性下图等价于上图 【重要】ref绑定组件标签
如果ref绑定了一个组件呢那么拿到的就是该子组件的vc。
app的vc有个 r e f 属 性 ref属性 ref属性ref属性上有一个该子组件的vc 总结 5.3 props配置项重要可用于父子组件间传输数据
如果不是父子组件还可以用其它方式传输数据。
需求引入
如下图所示Student.vue是一个组件。 我们想在下图中创建两个Student每个Student分别有不同的数据。比如第一个student数据就如上图但是第二个student数据 的name不叫张三了想改成李四。
其实这个需求就是复用Student.vue 这个组件。 解决方案如下图
自定义组件传入属性
props可用于组件间传输数据父组件传数据到子组件的data上
传入侧传入的属性一般是父组件(App.vue)也就是下图。
接收侧而写props接收参数的一般是子组件。其实接收完props相当于在自己的data属性中绑定了props的一些属性。 在想要被复用组件中data部分字段可以写成props。如下图所示共有三种写法
props的三种写法(从简单到复杂) 总结 这个props属性其实就是data里的属性。props可用于组件间传输数据父组件传数据到子组件的data上data在vc身上可以直接用this.xxx获取那么props里面的字段自然也可以。 但是props的字段优先级高于data的字段也就是说假如data和props有同名字段vue会帮我们优先渲染props的值。 props字段一旦确定不能被篡改。如果你想篡改请利用data篡改props。 【注意】props是只读的。Vue会对props的修改提出警告。如果你真要修改请利用data篡改props。用v-model双向绑定props是高危操作因为会引起props的修改
更多案例父组件利用v-for配合props动态建立多个子组件
父组件传入代码
ulMyItem v-for(todoObj,index) in todos :keytodoObj.id :todotodoObj/MyItem
/ultodos就是一个数组里面有一堆不同的对象。todoObj是数组的每个元素。
todo就是要传给子组件的自定义属性每次传输单个todoObj给子组件。注意要用 v-bind ( 绑定。
子组件接收代码
scriptexport default {name:MyItem,props:[todo]}
/script虽然没写data但是props里的todo已经可以按照data属性用了。
【重要】儿子如何给父亲传数据呢
答案是传入函数调用。父亲传给儿子一个函数然后儿子用props接该函数接到之后调用该函数向该函数里传入儿子的数据。这样儿子的数据就传递给父组件了。
父代码
templateulSon//将一个函数传给儿子儿子会调用该函数从而给父亲传输数据。:fatherFuncmyFunc //千万不能加小括号否则报错/Son/ul
/templatescript
import Son from ./Son.vue;export default {name: Father,components: { Son },methods: {myFunc(id){console.log(已经接收到儿子的数据了id) //输出123}},
};
/script子代码
button clicktransToFather点我把儿子的数据传给父亲/button //调用方法
script
export default {name:Son,data() {return {sonId:123 }},props:[fatherFunc],methods: {transToFather(){this.fatherFunc(this.sonId) //调用父亲给的函数将儿子的id传入。这样父亲就能收到儿子的数据}},
}
/script除了这种方式子给父传数据之外还可以移步第八章8、组件自定义事件$emit
【重要】兄弟组件之间如何传输数据
兄弟之间它们肯定有共同的父组件。比如AppApp一定是最顶级的父组件
所以可以通过A兄弟传给父亲父亲再传给B兄弟的方法来实现兄弟组件之间的传输
这是比较原始的传输方式。关于使用props父传子子传父兄弟互传详见尚硅谷视频
https://www.bilibili.com/video/BV1Zy4y1K7SH?p72
5.4 mixin混入
mixin需要解决的问题场景 局部引入混合
先编写 混合.js 文件 然后在一个组件中引入该混合 全局引入混合
你要是如下图这么写只要写在入口函数里那你所有的vc和vm都引入了该混合 总结 5.5 插件install
插件应用场景类似于java的导jar包
类似于java的导入jar包import java.util.Map;引用别人已经写好的强大工具
比如之前讲到的
过滤器全局指令混入给Vue原型上添加一个方法使得vm和vc共享该方法Vue.prototype.hello (){alert(你好啊)}
如下图所示建立插件 在入口处main.js全局引用插件只有入口处才能写大Vue也就是vm 然后任意组件vc都可以使用插件中给我们提供的强大功能了 总结 5.5 scoped CSS样式作用域
scoped解决的痛点
两个不同的组件class属性重名
类选择器也都一样但是颜色不同。
如果此时在app处同时引入这两个组件就会引发样式冲突 解决方案使style只对本组件生效
Add “scoped” attribute to limit CSS to this component only
!-- Add scoped attribute to limit CSS to this component only --
style scoped
h3 {margin: 40px 0 0;
}
ul {list-style-type: none;padding: 0;
}
li {display: inline-block;margin: 0 10px;
}
a {color: #42b983;
}
/style6、TODO List 案例 (原始版本)
需求 该案例所有知识点都之前学过。这里只给出代码位置
Giteehttps://gitee.com/da-ji/full_stack_developer大家需要可自取
总结 7、浏览器本地存储(localStorage,sessionStorage)
概念介绍
未登录的情况下搜索皮鞋关闭浏览器再重启仍然有该记录 说明浏览器将数据缓存到了本地硬盘上 查看该网站的在浏览器中的本地存储 纯JS实现浏览器本地存储功能
localStorage
下面的api是localStorage的一组功能还有一个兄弟叫sessionStorage功能一样。
!DOCTYPE html
htmlheadmeta charsetUTF-8 /titlelocalStorage/title/headbodyh2localStorage/h2button onclicksaveData()点我保存一个数据/buttonbutton onclickreadData()点我读取一个数据/buttonbutton onclickdeleteData()点我删除一个数据/buttonbutton onclickdeleteAllData()点我清空一个数据/buttonscript typetext/javascript let p {name:张三,age:18}function saveData(){localStorage.setItem(msg,hello!!!)localStorage.setItem(msg2,666)//存对象需要用JSON序列化一下localStorage.setItem(person,JSON.stringify(p))}function readData(){console.log(localStorage.getItem(msg))console.log(localStorage.getItem(msg2))const result localStorage.getItem(person)console.log(JSON.parse(result))// console.log(localStorage.getItem(msg3))}function deleteData(){localStorage.removeItem(msg2)}function deleteAllData(){localStorage.clear()}/script/body
/html就算浏览器整个关闭再重启localStorage仍然存在。
sessionStorage
这里的session和后端的session不同。session的意思为会话。假如适用sessionStorage那么就仅仅应用于一次会话。也就是浏览器一旦关掉sessionStorage就消失了
!DOCTYPE html
htmlheadmeta charsetUTF-8 /titlesessionStorage/title/headbodyh2sessionStorage/h2button onclicksaveData()点我保存一个数据/buttonbutton onclickreadData()点我读取一个数据/buttonbutton onclickdeleteData()点我删除一个数据/buttonbutton onclickdeleteAllData()点我清空一个数据/buttonscript typetext/javascript let p {name:张三,age:18}function saveData(){sessionStorage.setItem(msg,hello!!!)sessionStorage.setItem(msg2,666)sessionStorage.setItem(person,JSON.stringify(p))}function readData(){console.log(sessionStorage.getItem(msg))console.log(sessionStorage.getItem(msg2))const result sessionStorage.getItem(person)console.log(JSON.parse(result))// console.log(sessionStorage.getItem(msg3))}function deleteData(){sessionStorage.removeItem(msg2)}function deleteAllData(){sessionStorage.clear()}/script/body
/html总结 8、组件自定义事件$emit
父组件通过给子组件绑定自定义事件的方式来实现不用props就可以接收到子组件传递来的数据。
这种方法仍然做不到兄弟间直接传递。只能通过父子关系间接传递
根本原理是父组件将一个函数绑定在子组件vc实例上子组件通过
思考绑在子组件vc实例上是不是之前还学过一个 r e f s 属 性 没 错 。 使 用 refs属性没错。使用 refs属性没错。使用refs属性也能实现该功能。
绑定好几种写法
父组件绑定 如果你使用的是ref绑定可以用mounted 触发 mounted() { this. r e f s . s t u d e n t . refs.student. refs.student.on(‘atguigu’,this.getStudentName) //绑定自定义事件 }, 子组件使用this.$emit触发因为绑在this上所以可以使用this触发
如下图所示第一个参数是父亲指定的自定义事件名第二个参数到第n个参数是要传给父亲的形参们。可变参数列表 解绑this.$off 如果这样写this.$off()即为解绑所有的自定义事件什么参数都不传就是解绑全部
native修饰符绑定原生标签非自定义标签
父组件不仅仅能给子组件绑定自定义的标签还能绑定像clickxxx这种原生标签
但是像上面这种直接绑定是不生效的会被认为你绑了自定义标签此时必须这么绑定
click.nativexxx
总结
这种方法仍然做不到兄弟间直接传递。只能通过父子关系间接传递
事件的回调函数写在了父组件中 补充开发者工具事件视图 9、全局事件总线
概念
任意组件间进行通信
它并不是一个新知识点用到的所有知识上面全都有。只是一种思想罢了。如下图所示 上图中的X组件它什么活儿也不干只是为了各组件传递事件时用的。
X组件作为所有组件的协调者X必须保证全局可见性。
X应该放在哪里呢答案是vm身上。这样可以保证所有组件实例对象(vc)都可见
为什么理论基础是什么点我页内跳转Vue原型相关
原理
去main.js上面建立X
为什么要去main.js上操作因为只有main.js上才有VM 打开任意一个组件发现可以找到该X 到此为止原理讲解完毕但是实际开发中仍然不是这样绑定的接下来看实操
如何注册事件总线
在main.js上注册全局事件总线
这里的 b u s 就 是 前 面 说 的 x 。 约 定 俗 成 地 叫 做 bus就是前面说的x。约定俗成地叫做 bus就是前面说的x。约定俗成地叫做bus (bus英文译为总线)
//引入Vue
import Vue from vue
//引入App
import App from ./App.vue
//关闭Vue的生产提示
Vue.config.productionTip false//创建vm
new Vue({el:#app,render: h h(App),//在生命周期函数钩子上注册beforeCreate(){//安装全局事件总线这里的this即vm!Vue.prototype.$bus this; //$bus就是vm。vm可以调用$emit等。}
})使用事件总线任意组件传输数据
首先讲解知识点$on 使用 $on(eventName) 监听事件 使用 e m i t ( e v e n t N a m e ) 触 发 事 件 如 果 把 V u e 看 成 一 个 家 庭 相 当 于 一 个 单 独 的 c o m p o n e n t s ) 女 主 人 一 直 在 家 里 指 派 ( emit(eventName) 触发事件 如果把Vue看成一个家庭相当于一个单独的components)女主人一直在家里指派( emit(eventName)触发事件如果把Vue看成一个家庭相当于一个单独的components)女主人一直在家里指派(emit)男人做事而男人则一直监听( o n ) 着 女 士 的 指 派 ( on)着女士的指派( on)着女士的指派(emit)里eventName所触发的事件消息一旦 e m i t 事 件 一 触 发 emit 事件一触发 emit事件一触发on 则监听到 $emit 所派发的事件派发出的命令和执行派执命令所要做的事都是一一对应的。 o n 和 on和 on和emit是一对它们的形参也是一致的都是事件名一个是监听一个是触发。
直接看例子
Student组件和School组件是兄弟组件。
Student代码
scriptexport default {name:Student,data() {return {name:张三,sex:男,}},methods: {sendStudentName(){this.$bus.$emit(hello,this.name)}},}
/script当sendStudentName触发立刻使用事件总线( b u s ) 上 的 bus)上的 bus)上的emit方法触发事件发送。
School代码
当 e m i t 被 触 发 emit被触发 emit被触发on立刻接收触发回调
由于 o n 和 on和 on和off是一对在被摧毁之前养成使用$off解绑的好习惯。
scriptexport default {name:School,props:[getSchoolName],data() {return {name:尚硅谷,address:北京,}},mounted() {this.$bus.$on(hello,data {console.log(我是school组件我收到了来自兄弟的数据data) //输出”张三“})},//好习惯一旦该vc被干掉了解绑自定义事件。//思考为什么不在student上面调用摧毁因为需要考虑多个组件同时监听了school这是一对多关系。//$on和$off是一对beforeDestroy() {this.$bus.$off(hello)},}
/script总结 10、消息订阅与发布
会了之前的内容这一章甚至都没什么好讲的简单的出奇…
和全局事件总线是同类技术。实现组件间通信
其实就是借助第三方库来实现。第三方库铺天盖地用哪个都行。
这里我们选用pubsub-js (全称为publish subscribe发布和订阅) 。
注意这个pubsub.js也可以使用于reactangular 等框架。
安装该库
npm i pubsub-js
使用该库(常用的只有三个方法subscribe订阅unsubscribe 取消订阅publish发布)
Student组件和School组件是兄弟组件。
Student代码
scriptexport default {name:Student,data() {return {name:张三,sex:男,}},methods: {sendStudentName(){// this.$bus.$emit(hello,this.name)pubsub.publish(hello,666)}},}
/script当sendStudentName触发立刻触发事件发送。
School代码
在被摧毁之前养成使用unsubscribe 解绑的好习惯。
scriptexport default {name:School,props:[getSchoolName],data() {return {name:尚硅谷,address:北京,}},mounted() {// this.$bus.$on(hello,data {// console.log(我是school组件我收到了来自兄弟的数据data)// })this.pubId pubsub.subscribe(hello,(msgName,msgData){console.log(有人发布了msgData)})},beforeDestroy() {//取消订阅pubsub.unsubscribe(this.pubId)// this.$bus.$off(hello)},}
/script总结 11、$nextTick 场景和绕开规则链一致
你想在DOM渲染后对新的DOM进行某些操作但是你这个操作又和修改dom封装在同一个函数中。你现在想绕过规则链。那么就有两种办法 1、 setTimeout setTimeout(() {//对新的DOM进行操作
}, 1000);延时的方式绕过规则链 2、使用$nextTick this.$nextTick(function(){this.$refs.inputTitle.focus() //对新的DOM进行操作比如聚焦
})这两种方法都可以本质其实就是绕开规则链。
12、过渡和动画
场景
点击按钮切换显示/隐藏效果 其实就是Vue配合CSS。
HTML关键字
transitionn.过渡;转变;变革;变迁
transition-group
CSS绑定关键字
xxx-enter-active xxx-leave-active 还有一些高阶用法如下图(下图是Gitee代码位置)
完整代码见Test2.vue
style scopedh1{background-color: orange;}/* 进入的起点、离开的终点 */.hello-enter,.hello-leave-to{transform: translateX(-100%);}.hello-enter-active,.hello-leave-active{transition: 0.5s linear;}/* 进入的终点、离开的起点 */.hello-enter-to,.hello-leave{transform: translateX(0);}/styleAnimate.css
animate adj.有生命的;有活力的;有生气的
它是一个成型的动画库只需要引入即可。
官网http://www.animate.net.cn
首先需要安装执行命令
npm install animate.css
使用示例代码位置上图中的Test3.vue
这里的教程是vue的transition标签配合Animate.css这个库去使用的。
这样我们就不用亲手写css了只需要自己从Animate.css按需取得即可。
总结 四、Vue ajax
1、前置知识和准备
你至少要懂
原生ajaxpromiseaxios跨域的概念
2、Vue中axios的基本使用
使用axios发一个get请求假设你vue前端应用跑在8080上你要发get请求的地址是5050
scriptimport axios from axiosexport default {name:App,methods: {getStudents(){//假设你vue前端应用跑在8080上你要发get请求的地址是5050axios.get(http://localhost:5000/students).then(response {console.log(请求成功了,response.data)},error {console.log(请求失败了,error.message)})}}
/script
发现跨域了违反同源策略 跨域规定了三个东西必须一致协议名主机名端口号否则跨域
【补充知识】ajax跨域问题
什么是跨域 浏览器从一个域名的网页去请求另一个域名的资源时域名、端口、协议任一不同都是跨域 遇到跨域可以正常发出请求但是浏览器拒绝接收响应。
跨域限制
1、无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB2、无法接触非同源网页的 DOM3、无法向非同源地址发送 AJAX 请求可以发送但浏览器会拒绝接受响应
解决跨域 cors解决后台解决 写服务器的人在返回响应的时候给你几个特殊的响应头。浏览器解析到特殊响应头的时候就会放行该响应。 jsonp解决 借助script标签里面的src属性引入外部资源的时候不受同源策略限制来实现。而且只能解决get请求的跨域问题。 配置一个代理服务器
使用vue-cli搭建代理服务器
方法一简单
直接看官网 配置好之后然后将你要请求的地址不要直接请求原服务器而是直接指向代理服务器
还是以上面为例 方法二
上面这种配置代理的方式只能配置一台代理服务器下面介绍另一种更强大的方式
还是去官网看 里面还可以自定义许多参数 参数之代理前缀 作用很简单如下图 参数changeOrigin:false 默认为true 控制代理服务器是否撒谎更换自己代理服务器的端口也就是请求头中的host值 参数ws默认true 支不支持webSocket
总结 综合案例模拟请求
需求 该综合案例模拟请求的是一个github的接口。不过由于众所周知的原因中国大陆是访问不到Github的。于是我使用Node express搭建了一个简易服务器该案例只需要请求我本人的服务器即可。
服务器源码
const express require(express)
const app express()app.use((request,response,next){console.log(有人请求Github服务器了);// console.log(请求来自于,request.get(Host));// console.log(请求的地址,request.url);next()
})app.get(/github,(request,response){let id request.query.id;const users [{imgurl:https://img0.baidu.com/it/u3117693326,3861562318fm253fmtautoapp138fJPEG?w359h239,name:大吉},{imgurl:https://gimg2.baidu.com/image_search/srchttp:%2F%2Fpic3.zhimg.com%2F50%2Fv2-c7875263af61123a7085ac188dcfef69_hd.jpgreferhttp:%2F%2Fpic3.zhimg.comapp2002sizef9999,10000qa80n0g0nfmtauto?sec1650173874t3e72978d1e5fc306ac9cd3bc506e5a38,name:田所浩二1},{imgurl:https://gimg2.baidu.com/image_search/srchttp:%2F%2Fpic4.zhimg.com%2F50%2Fv2-8b3b38fea6c9f9668c4118f04c059da5_hd.jpgreferhttp:%2F%2Fpic4.zhimg.comapp2002sizef9999,10000qa80n0g0nfmtauto?sec1650173874tcabec2f0ad269cc6ca4e3d3a0c65b2ae,name:坂田},{imgurl:https://img0.baidu.com/it/u1908604312,998341899fm253fmtautoapp138fJPEG?w667h500,name:香蕉君},{imgurl:https://gimg2.baidu.com/image_search/srchttp:%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2Fc4a30e83dee6e8bc4eeb599c1bdf31e4fa937d8b.jpgreferhttp:%2F%2Fi0.hdslb.comapp2002sizef9999,10000qa80n0g0nfmtauto?sec1650173992t251951e5eb80e1d2006de2f8b6b53564,name:保加利亚妖王},]console.log(服务器已经收到客户端传来的id:${id},并返回了一堆用户信息);const resp {id: id,users: users}response.send(JSON.stringify(resp))
})app.listen(5000,(err){if(!err) console.log(GitHub服务器启动成功了,请求地址为http://localhost:5000/github);
})
代码位置 最终效果 3、vue-resource
和axios同类技术。只不过是vue官方维护的。
它是一个插件使用的时候需要Vue.use
安装npm i vue-resource 使用插件 可以发现他的API和axios是一致的也是promise风格的。仅作了解
4、slot插槽
其实就是组件标签内部套用其它标签。
最简单的插槽
父组件代码
子组件代码
slot可以打标识 具名插槽
有名字的插槽适用于多个插槽
其实就是指定name属性 template v-slot:xxxxx
加一个template标签最后解析成html的时候该标签会不显示。而且可以使用v-slot这个标签。
但是你不加template标签请正常使用slotxxx就不能使用v-slot了 作用域插槽template scopexxx
slot-scope也可以写法不同罢了
场景如下图 方法很简单在子插槽上加标签。这样就可以将数据传给插槽的使用者了 父组件如何接收呢如下图 总结
插槽其实也是父子组件通信的一种方式 五、vuex
1、基本概念和应用场景
首先它是一个插件。使用 Vue.use(Vuex)引入是一种组件间通信的方式适用于任意组件间通信。
使用场景 当多个组件依赖于同一个状态变量或者来自不同组件的行为需要变更同一个状态其实就是多个不同组件的读写最好应用vuex
2、[面试】Vuex工作原理
对下图的解释 store其实就是下图VuexActions,Mutations,State的父亲它们三个之间的状态转换灰色箭头的api由store提供store.dispatchstore.commit等等 Actions一个普普通通的Object类型对象vc的改变会先通过store.dispatch()将值传递给action。然后经由action通过store.commit()发送给Mutations。 Actions还可以通过ajax和后端交互就是下图中的Backend API通过后端接口拿数据也是组装到Action中 如果不调用Backend APIVC可以直接将数据交给Mutations绕开Actions。也就是说Actions是可以跳过的 Mutations(n. 突变变更)它是一个Object类型的对象。负责真正处理加工修改数据处理完成后将处理完成的数据传入State中 Vue的开发工具Devtools监测的就是Mutations里的数据 State也是一个Object类型的对象vuex会将里面的数据进行渲染还给VC更新VC 3、搭建vuex环境
你在vue2的项目中只能安装vue3版本
你在vue3的项目中只能安装vue4版本
所以这里安装vue3npm i vuex3
引入vuex
import Vuex from vuex
Vue.use(Vuex)在目录结构中创建store文件夹或是创建vuex文件夹这是约定俗成的规范 store中的index.js内容样例
根据上面的工作原理store中应该至少包含 actions,mutations,state这三个东西然后将这三个东西塞入new出来的store中最后再暴露store
//该文件用于创建Vuex中最为核心的store
import Vue from vue
//引入Vuex
import Vuex from vuex
//应用Vuex插件
Vue.use(Vuex)//准备actions——用于响应组件中的动作
const actions {/* jia(context,value){console.log(actions中的jia被调用了)context.commit(JIA,value)},jian(context,value){console.log(actions中的jian被调用了)context.commit(JIAN,value)}, */jiaOdd(context,value){console.log(actions中的jiaOdd被调用了)if(context.state.sum % 2){context.commit(JIA,value)}},jiaWait(context,value){console.log(actions中的jiaWait被调用了)setTimeout((){context.commit(JIA,value)},500)}
}
//准备mutations——用于操作数据state
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 //当前的和
}//创建并暴露store
export default new Vuex.Store({actions,mutations,state,
})下面的代码段是main.js(vm入口)
引入完成后你new vm的时候就可以创建一个store配置项
//引入store
import store from ./store//创建vm
new Vue({el:#app,render: h h(App),store,beforeCreate() {Vue.prototype.$bus this}
})
4、实操计算程序使用vuex
代码位置 一图完全解析
其实类似于Java里SpringBoot的三层架构。 Controller层子组件vc中的函数 Service层Action层。这一层可以省略但是最重要的是这一层可以与后端API进行交互不交互时可以省略 Dao层mutations层 DataBasestate层 dispatch的封装
其实就跟我们把一大坨代码进行封装一样如下图所示可以在Service层抽出来代码封装 5、Vuex开发者工具使用
它检测的其实就是Mutations的数据 6、getters配置项
一图便知
当state中数据要微调的时候可以使用getters再加工也可以用其它办法实现 7、mapState、mapGetters、mapActions、mapMutations
引入
import {mapState,mapGetters,mapMutations,mapActions} from vuex
【理论基础】一个ES6简写 这样写obj里面就同时有了a,b,x,y
mapState、mapGetters
【不懂看上面的简写】mapState一图详解其实就是简写计算属性罢了 mapGetter其实就是简写getter罢了写法和语法和mapState完全一致故不做演示
总结 mapMutations、mapActions
mapMutations其实就是借助mapMutations生成对应的方法方法中会自动调用commit去联系mutationsmapActions其实就是借助mapActions生成对应的方法方法中会自动调用dispatch去联系actions
下面一图便知 8、vuex模块化namespace、ajax请求服务器
场景你不能一个store里面把所有actions、mutations、state、getters等全都写了正常的项目比如人员模块商品模块等等会封装成不同的js文件。
需要的语法支持是namespace关键字默认为false你需要将其设置为true这样才能被前面说的mapState等等东西自动生成映射关系
二图案例解析 图1store模块化配置以及Actions层中使用axios请求外部服务器数据 如下图所示Vuex的入口index.js被拆成了几个独立模块index.js只需要引入模块即可 使用axios发送请求给外部服务器也很简单只不过被分到了Action层去做 图2VueComponent组件如何使用上图中的Vuex配置 下图承接上图两张图案例变量名和交互啥的都是一样的。
案例效果 案例代码位置 9、总结模块化 六、vue-router 路由
1、概念
以路由器为例一组key-value对应关系就是一个路由。多个路由被一个路由器进行管理。
路由route路由器router 单页面(SPA Single Page Application)应用概念 不管怎么点击浏览器不发生全部刷新/跳转到其它页面ajax但是浏览器地址栏却发生变化。 为什么浏览器地址栏发生变化呢?方便用户复制网址时能够带着它的自定义页签方便用户体验。 整个应用只有一个完整界面 点击页面导航不会刷新页面数据交换通过ajax请求完成
一般的单体系统SSMthymeleaf是很难做到这种局部刷新同步更新地址栏的。要么就是全部局部刷新要么就是直接返回一个视图全部地址栏带整个页面刷新
如下图所示 这里我们通过Vue-router完成。
key为路径value可能是function或者component
2、安装\引入\基础使用
只有vue-router3才能应用于vue2vue-router4可以应用于vue3中
这里我们安装vue-router3npm i vue-router3
引入vue-router在入口js中引入import VueRouter from vue-router
vue.use(VueRouter)
需求引入
下面我们来实现下图这样一个场景 2.1 router的入口JS和基础引入 2.2 router-link、router-view、active-class
使用路由实现上面的切换页签局部刷新并更新地址栏需要使用router-link to/xxx这个标签如下图所示其本质会在html页面给翻译成a标签
下图作用于App.vue 配置active-class
如下图示配置了active-class这个html属性谁被选中里面的值就会被加在哪个class身上 上图的逻辑是About被选中那么它的class最终会变成 class“list-group-item active”Home被选中同理它的class也会追加上后面的active-class内的值。
配置replace属性 2.3 目录结构几个注意点 注意到上面的App.vue其实并没有使用之前熟悉的标签方式加载组件。而是直接使用router-view来加载组件的。因此需要用router-view来加载的组件们我们称之为路由组件需要显式使用标签来的我们称为一般组件。 路由组件一般放在pages文件夹下。虽然它们是 .vue 格式的文件但是更像一个个的页面。 通过切换方式隐藏了的路由组件默认是走一个销毁流程的。需要的时候重新挂载可以用beforeDestroy()来验证的确被销毁了 每个组件有自己的$route属性里面存储自己的路由信息 每个组件上有全局的$router这是全局唯一共享的
3、嵌套路由children
场景其实就是路由的套娃一个路由套一个路由 图解
注意写一级路由需要加 / 二级路由不能加 / 总结 4、路由传参之query参数
每个组件有自己的$route属性里面存储自己的路由信息
接收参数就存放在this.$route.query中
那么传入参数呢使用:to 看上图的传参其实有两种写法 字符串写法 众所周知使用绑定to那么双引号里面内容是作为JS表达式解析的。然后我们又嵌套了这种模板字符串。模板字符串使用${ }来包装参数。所以最终的字符串就是活的。 对象写法 众所周知使用绑定to那么双引号里面内容是作为JS表达式解析的。所以可以直接写对象。
5、路由传参之params参数
前置知识是下面的 6、命名路由name属性
ajax不仅能用 传参还能在路径中直接传参。
比如 /student?id1 也可以这么传/student/id/1 这叫params参数。 特别注意路由携带params参数时若使用to的对象写法必须使用 下面6、命名路由name属性的方式 6、命名路由name属性
太简单了就是为了简化写一长串路由/home/new/message/1 这种直接通过写name简化 7、路由的props配置
还记得之前学过的props吗它可以应用于路由中
下图一图便知 总结 8、编程式路由导航($router)
之前实现路由跳转必须借助router-link标签我们知道该标签实际上就相当于一个a标签。
那么如果我们想在一个button按钮上绑定路由跳转那怎么办呢就不能用router-link了。
编程式路由导航和router-link标签一样也可以 配置replace属性
编程式路由导航其实就是将router-link的配置项写入自定义函数借助所有组件全局共享的routerthis.$router来操作。 还可以借助$router的其它API实现前进一步后退一步任意跳转
templatediv classcol-xs-offset-2 col-xs-8div classpage-headerh2Vue Router Demo/h2button clickback后退/buttonbutton clickforward前进/buttonbutton clicktest前进3步/button/div/div
/templatescriptexport default {name:Banner,methods: {back(){this.$router.back()// console.log(this.$router)},forward(){this.$router.forward()},test(){this.$router.go(3)}},}
/script9、缓存路由组件(keep-alive标签)
场景 造成上述问题的原因其实很简单之前讲过一旦切换组件之前的那个组件直接就被销毁了再次切换回来就重新创建一个新的组件。
所以缓存路由组件就是让其切换的时候保持挂载不销毁就行了 如果你想缓存多个路由组件这么写(要用v-bind绑定)
keep-alive :include[News,Message] 10、两个新的生命周期钩子仅在路由有
activated()、deactivated() 当路由被激活/失活
之前讲过一旦切换组件之前的那个组件直接就被销毁了再次切换回来就重新创建一个新的组件。
在第9节讲过如果你不想让这个组件销毁可以使用缓存路由组件。
但是你仍然想让页面切换的时候产生动作和行为那就可以使用 activated()、deactivated() 当路由被激活/失活时控制该组件。
这样你就算缓存了路由组件路由组件不会被销毁那么仍然切换的时候会执行激活和失活。 示例
scriptexport default {name:News,data() {return {opacity:1}},/* beforeDestroy() {console.log(News组件即将被销毁了)clearInterval(this.timer)}, *//* mounted(){this.timer setInterval(() {console.log()this.opacity - 0.01if(this.opacity 0) this.opacity 1},16)}, */activated() {console.log(News组件被激活了)this.timer setInterval(() {console.log()this.opacity - 0.01if(this.opacity 0) this.opacity 1},16)},deactivated() {console.log(News组件失活了)clearInterval(this.timer)},}
/script11、路由守卫
作用控制路由的权限
比如你不登录淘宝你就不能点击个人中心。就算你在地址栏输入了个人中心的那个路由taobao.com/myCenter也会给你强制跳转到登录页面。
11.1 全局路由守卫
为什么说是全局呢因为需要在路由器入口处index.js配置这样你所有的路由在此注册都会调用到路由守卫函数。
全局前置路由守卫router.beforeEach()
路由初始化时被调用
或每一个路由(route)被切换到之前路由器(router)都会帮每个route调用这个函数。
前置路由守卫作用于拦截只要不调用next()就不放行
全局后置路由守卫router.afterEach()
初始化的时候被调用、每次路由切换之后被调用。用的不多
案例读取浏览器本地暂存localStorage, 如果发现有键值对为 ‘school’‘atguigu’ 的一组键值对那么就可以判定用户已经登录允许用户访问路由。 代码实现 上图中的关键词
to路由的终点 meta路由元信息/路由自定义信息可以存放一些特殊的自定义数据标识等等但是必须放在mata里属性名必须是meta。 from路由的起点next放行
11.2 独享路由守卫beforeEnter
独享路由守卫只有前置没有后置之说
它其实就是将全局前置路由守卫的代码挪到路由注册的地方而已 11.3 组件内路由守卫
之前的路由守卫是配置在路由入口index.js内组件内路由守卫顾名思义就是配置在VueComponent里面的路由守卫
beforeRouteEnter() 、beforeRouteLeave() 离开时的守卫有next可以决定放行与否。
12、路由器的两种工作模式(history、hash) hash 模式 路由器的 /#/及其之后的路径都叫做路径的hash值。 其特点是不会随着服务器的请求发给服务器。也就是只有#之前的会发给server#后面的并不会 默认就是hash模式如果你想修改成history模式如下图(mode:‘history’) history模式 会随着服务器的请求发给服务器 没有 /#/ 兼容性略差。 兼容性差的理解在下面的前端项目上线流程可以解释。这里非常重要 。 兼容性差的理解在下面的前端项目上线流程可以解释。这里非常重要 。 兼容性差的理解在下面的前端项目上线流程可以解释。这里非常重要 。
前端项目上线流程
本质上就是将你所写的全部项目打包。打包后会生成.html css, js文件。只有这种纯粹的文件格式才能被浏览器解析。而.vue格式的东西浏览器压根不认识。
这个过程是webpack的知识点。 执行命令 npm run build即可。
打包完后会生成一个 dist 文件夹打开该文件夹就是 html,css,js文件。 打包后的东西必须去服务器上进行部署动作。
这里的部署可以有两种部署方式
合并部署静态资源和服务器打在同一个包中比如springboot的jar包、nodejsexpress构成的微型服务器均可分开部署dist和服务器代码分开打包部署
下面用nodejsexpress的简易服务器演示部署 新建一个文件夹mkdir vue_deploy然后进入该文件夹中cd vue_deploy 执行命令npm init 新建一个js文件作为服务器入口touch server_test.js server_test.js内部编写代码 const express require(express)
const app express()//专门指定静态资源必须
//专门指定静态资源必须
//专门指定静态资源必须
app.use(express.static(__dirname/static))app.get(/person,(request,response){const resp {id: 123,users: users}response.send(JSON.stringify(resp))
})app.listen(5000,(err){if(!err) console.log(服务器启动成功了,请求地址为http://localhost:5000/person);
}) 在根目录新建文件夹 static 因为上面指定的静态资源目录就是 /static 将dist内所有的文件拷贝至static 【可选】npm i express安装express 执行命令node server_test.js启动服务器 访问http://localhost:5000可以直接看到你的Vue前端项目
这样做有一个问题如果你启用的路由器是history模式真正上线的时候会报错服务器会请求并不存在的资源 如上图所示如果你是history模式那么下图中方框圈出来的全部会被当成一次服务器请求请求服务器资源但是我们知道上图中方框圈出来的只不过是我们的纯前端路由而已按理说和后端一毛钱关系没有。后端不应该根据这串链接请求服务器的资源。服务器也没有该资源。所以会报一个可想而知的错误如下图所示 解决方案其实非常简单将路由器的工作模式改成hash则问题解决hash只有#之前的会发给服务器#后面的并不会
如果我非得想用history模式咋办也可以。不过这个问题需要抛给后端来解决。
后端通过匹配匹配哪些请求是纯前端的然后对这些发到后端来的请求不予响应。即可。
在NodeJS服务器中可以使用库connect-history-api-fallbackJava写的后端中也有对应的类库解决。Nginx也是天生用来解决这一问题的它通过配置可以自动帮我们分辨哪些是后端需要响应的路由哪些是纯前端路由
总结 七、Vue UI 组件库
Vue适配组件库推荐
组件库之所以叫组件库一定是为了适应组件化开发用的组件库。所以Vue有Vue适配的组件库React有React适配的组件库。
由于是组件嘛所以全都需要用到Vue.use(XXX)
下面介绍的全都是Vue适配
移动端
Vant https://youzan.github.io/vantCube UI https://didi.github.io/cube-uiMint UI https://mint-ui.github.ioNutUI 京东移动端Vue组件库
PC端
Element UI https://element.eleme.cnIView UI https://www.iviewui.com
特别推荐钉耙tinper-bee
在我的React笔记中还要再次推荐一次
http://bee.tinper.org/design-new/ tinper-bee 是一套基于 React.js 的开源组件库它从丰富的企业级中后台应用场景中实战沉淀而来为复杂应用的快速开发提供一致性 UI 解决方案。 组件的全部引入和按需引入
以 Element UI为例如果你全部引入
//引入ElementUI组件库
import ElementUI from element-ui;
//引入ElementUI全部样式
import element-ui/lib/theme-chalk/index.css;
//应用ElementUI
Vue.use(ElementUI);会发现臃肿无比 所以我们需要按需引入 样例babel.config.js
module.exports {presets: [vue/cli-plugin-babel/preset,[babel/preset-env, { modules: false }],],plugins:[[component,{libraryName: element-ui,styleLibraryName: theme-chalk}]]
}
main.js中按需引入
import Vue from vue;
import { Button, Select } from element-ui;
import App from ./App.vue;Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
/* 或写为* Vue.use(Button)* Vue.use(Select)*/new Vue({el: #app,render: h h(App)
});按照官网指引做就好了
八、展望 Vue 3.0
课件位置
Vue/资料含课件/01_课件/vue3快速上手.md
【未完待续】
后记
本文全套资料、案例、源代码、插件已上传至Giteehttps://gitee.com/da-ji/full_stack_developer大家需要可自取。
不得不说尚硅谷的这套课程的确是良心之作而且官方居然还开源出来让大家都可以学习实在是难能可贵。
如果大家在学习本篇文章的同时有疑问欢迎在评论区讨论和留言也可以关注我日后我还会陆续更新完Vue3.0、Nod eJS、React等内容。