框架的作用:
- 1.为了替代jquery
-
- 内部出了模块问题,让开发者用起来更简单
-
- 直接调用就可使用
-
- 高效。不用自己写代码,并且运行快速
-
- 浏览器兼容性好
-
- 成本低
适用前端框架的规则
-
- 目录
- public/static-->静态资源文件夹-->不会被webpack之类的工具编译 - img
- stylesheet
- js
- 字体
- src 源代码开发目录,也就是我们操作的主要核心目录
- common 公共资源文件夹
- assets 项目开发所需要的的静态文件夹-->会被webpack之类的工具编译
- img
- stylesheet
- js
- component 公共存放目录
- Tab 项目头部
- TabBar 项目底部
- List 列表
- router 路由配置文件夹
- store 项目数据仓库文件夹
- utils 项目的公共函数封装库
- 大小写转换
- 时间、日期、REM、cookie等
- pages/views 项目核心页面
- home
- shopcar
- user
- catgory
- detail
- xxx
vue的发展历史
-
- 1.0 -->2014
-
- 2.0 -->2016
-
- 3.0 -->2019
vue是一个MVVM框架,实现了双向数据绑定
-
- 别名:
- 深入响应式原理
- 双向数据绑定原理
- 数据响应原理
-
- 文字叙述:
- Vue是通过数据劫持来实现深入响应式原理的,数据劫持指的是通过js的Object.dafinePerproty中的getter 和setter对数据进行拦截的,当第一次绑定数据时,会触发getter,对象的属性值改变时,会自动触发setter,进而修改视图内容
插值表达式(模板语法)
-
- 表达式语法一般会用在哪里?
- 使用形式:参考后端 -ejs语法:<% %>
- 2.js的支持
- null和undefind是不会显示的,其他数据类型都是支持的,可以显示
- 凡是全局对象绑定在window身上的在表达式中都不能使用
- 3.如何使用:
- 内容中使用
- 属性中使用
- 指令
- 目的
- 操作DOM(因为命令是直接绑定在DOM上的)
- 属性的写法
-
- v-html:可以解析xml类型数据
-
- v-text:可以解析普通数据
- 双向数据绑定效果指令
- v-model (表单控制绑定)
- 只能用于表单
- v-model默认绑定value属性
- VM改变V随之改变
- V改变,VM也随之改变
- 使用单向数据绑定来实现双向数据绑定
- <input type="text" :val="msg" v-on:input="change"
- p>{{msg}} p/> -对{}{}的支持:
number: {{ num }}
-string: {{ str }}
-boolean: {{ bool }}
-null: {{ nul }}
-undefined: {{ und }}
-object: {{ obj.name }}
-array: {{ arr[ 1 ] }}
-function: {{ fn() }}
-{{ arr.join(',') }}
-三目运算符: {{ 5 > 3 ? '成立' : '不成立' }}
-短路原则: {{ 5 < 3 && '成立' || '不成立' }}
- 单向数据绑定 - v-bind:="" - 将vue中数据赋值给属性值 - 简写: - :xx="" - 实现类名绑定: - 正常写法: - - 对象写法 - :class="{}" - 数组写法 - :class="[]" - 实现样式绑定: - 正常写法: - - 对象写法 - :style="{}" - 数组写法 - :style="[]"
- 流程控制-条件渲染
-
- v-if
- 控制的事元素的存在与否
-
- v-else-if
-
- v-else
-
- v-show条件展示 -控制的事元素的display:none属性 -以初始条件为假时,v-show的性能损耗较高
- 频繁切换使用:v-show
- 不是频繁切换:v-if -例子: -判断 -条件展示 -v-show = "f" 老王 -条件判断
- 单路分支 -v-if = "flag" 距离放假2周
- 双路分支
- v-if = "flag"双路 - 1
- v-else 双路 - 2
- 多路分支
- v-if = "text === 'A'" A
- v-else-if = "text === 'B'" B
- v-else> C
- script:
- new Vue:({
-el:""
-data: { - f: false, -flag: false, -text: 'A' )}
-
- 流程控制-循环(列表渲染)
- 列表渲染参数最多可以写三个,分别为item,key,index
- 列表渲染,要在渲染的元素身上加一个key,作为这个元素的唯一标识
- 例子:
- 数值
- li v-for="(item,index) of num" :key=item.id>{{item }} -- {{ index }}</li
- 字符
- li v-for="(item,index) of str" :key=index>{{item }} -- {{ index }}</li -普通对象
- li v-for="(item,key,index) of obj" :key=index>{{item }} --{{key}}-- {{ index }}</li
- 数组
- li v-for="(item,index) of arr" :key=index>{{item }} -- {{ index }}</li -普通json数据
- li v-for="(item,index) of json" :key=index>{{item }} -- {{ item.id }}</li
- 多层数据结构
- ul> li v-for = "item of nestData" :key = "item.id"> h3> {{ item.name }} </h3
-
{{ ele.name }}
- 数值
事件处理器
- vue是通过{}{}语法来实现数据绑定效果的
- 格式:
- v-on:事件类型='事件处理程序'
- 简写
- @:事件类型='事件处理程序'
- 使用:
- 先申明在绑定事件
- 先写好事件处理程序,然后再去绑定原生身上
- 《button @click = "handler"> 普通事件 </button》
- li v-for ="(item,index) of todos" :key = "item.id" button @click = "事件处理程序(index,item.task)"> 输出索引和任务内容 </button 《/li》
- 如果一个函数中既有普通函数,又有事件对象
- 使用
event,10 )"> 普通参数 + 事件对象 </button
- 使用
- 先申明在绑定事件
事件修饰符
- 事件修饰符
- stop stopPropagation()
- prevent preventDefault()
- self
- xxxx
- 重点记忆
- stop
- prevent
- slef
- once -使用
- @click.stop
- @click.once
- @click.xxx
按键修饰符
- 按键修饰符是对键盘 事件的修饰
- 键盘事件:keyup keydown keypress(按下再放起来之后)
- 使用
- @keyup="msg"
- @keyup.13="msg"
- @keyup.enter="msg"
- @keyup.p="msg"
- @click.right="msg"
- xxx
自定义事件
- vm.$on-->自定义事件名称,自定义事件的事件处理程序
- $emit-->触发自定义事件
自定义指令
- 全局定义
- Vue.directive(指令名称,指令的配置项)
- Vue.dirctive('focus',{
- bind(el,binding,vnode,oloVnode),
- inserted(el,binding,vode,oldVnode){
- console.log( inserted -> el", el) // 当前元素
- console.log("西阁: inserted -> binding", binding) // 指令的全部信息
- console.log("西阁: inserted -> vnode", vnode) // 指令的元素对应的虚拟节点console.log("西阁: inserted -> oldVnode", oldVnode) // 指令的元素对应改变前的虚拟节点 } if ( binding.modifiers.xige ) { el.focus() } else { el.value = binding.value el.style.background = '#ccc' } },// inserted表示指令绑定的元素被插入页面时触发 // updated () {}, // 指令绑定的元素或其子元素发生改变时触发 // componentUpdate () {}, // 指令绑定的组件或其子组件发生改变时触发 unbind () { // console.log( 'unbind') } // 指令绑定的元素被删除 })
- 局部定义
- directives:{指令名,指令的配置}
computed 计算属性
- 是对已有数据进行计算和赋值
- 好处
- 1.逻辑还是交给vm处理
-
- 在模板中,使用全局变量一样使用
- 3.如果计算是普通方法,那么这个计算不能改,安全,稳定
-注意
-计算属性如果是一个方法,这个方法后不加()
-
{{ num*2 }} </p》
watch 侦听属性
- watch: {
firstName ( val ) {
this.fullName = val + this.lastName
},
lastName ( val ) {
this.fullName = this.firstName + val
},
num: {
deep: true, // 深度监听
handler ( val ) { // 当num发生改变时,触发的方法 console.log( val ) } } } - 总结:如何使用
-
- methods:事件处理程序
-
- watch又大量数据交互和异步处理时进行
-
- computed
- 有逻辑处理
- v中象全局变量一样使用
混入
-
- 全局混入 Vue. minxin(不推荐)
-
- 局部混入 minxins
- 作用:
- 将选项中某一个或是多个单独分类出去管理,让职能更加单一高效,符合模块化思想
key的重要性
-
- sameVode函数-->决定当前节点是否patch,如不相同,则节点将会销毁/添加
-
- createKeyToOldIdx 函数-->该函数的作用是 当 对比两个子节点数组时,建立 key-index映射代理遍历查找 sameNode.提高性能。
- 总结
- 1.key能够决定节点是否应该被删除、添加、修改,当节点被删除、添加时,会发生以下事件
- 完整地触发组件的生命周期钩子
- 触发过度
-
- 对比两个子节点数组时,建立key-index映射代替遍历查找sameNode,提高性能
- 3.key值是每一个vnode的唯一标识,以便diff算法进行统计比较,我们可以更快的拿到oldVnode中相对应的节
component:用来注册组件
- 作用:
- 组件化是为了解决多人协作冲突问题
- 复用
- 概念:
- 组件是一个html、css、js、img等的一个聚合体
- 属于扩展性功能
- 通过Vue.extend()来扩展
- 注册当前组建的名字,配置项:配置当前组件的模板以及组件所使用数据方法等等
template:模板
-
- 特点:有且只能有一个根节点
-
- 官方推荐的模板写法,写在script标签内,一定要定义类型是x-template
- 《script type="x-template" id=""》
-
- 在vue内配置template会替换掉我们当前绑定的元素
- 适用于组件的嵌套
组件通信
- 为什么要进行通信
- 组件是一个聚合体,将来项目要合并,那么必然各个组件之间需要建立联系,支个联系就是数据通信
- data为什么是一个函数?
- 组件是一个聚合体,也是一个整体,他需要一个独立的作用域,也就是他的数据需要是独立的,目前js的最大特点是函数式编程,而函数恰好提供一个独立作用域,所以我们data在除根组件外都是函数
- 为什么data函数需要返回一个返回值,返回值还是对象,不能是数组吗?
- vue通过es5的Object.definePerproty属性对一个对象进行getter和setter设置,而data选项是作为VUE深入响应式核心的选项
- 分类
- 父子组件通信
- 过程:
- 父组件将自己的数据通v-bind绑定在子组件身上
- 子组件通过props属性接收
- props属性数据验证
- 验证数据类型
- type:数据类型
- 验证数据大小(判断条件)
- validator(val){ return val>0 }-->验证函数
- 验证数据类型
- 子父组件通信(通过事件形式)
- 是通过自定义事件
- 事件的发布
- 通过绑定元素身上实现
- 事件的订阅
- 通过this.$emit触发
- 事件的发布
- 是通过自定义事件
- 总结:
- 父子组件通信、子父组件通信理解:
- 父组件传给子组件的数据不能够直接在子组件内修改,能够修改父组件属性的只有父组件自己
- 就是父组件通过props向下传递数据给子组件
- 子组件如何与父组件通信:
- 子组件要通过$emit()发布事件,然后父组件通过@子组件发布的事件,去执行对应的方法修改数据
- 父组件传给子组件的数据不能够直接在子组件内修改,能够修改父组件属性的只有父组件自己
- 父子组件通信、子父组件通信理解:
- bus事件总线
- 使用场景: 可用于非关联组件之间的通信
- 作用:
- 触发事件和监听事件,巧妙而轻量的实现了任何组件间的通信
- 具体实现方式
- var Event=new Vue();
- Event.$emit(事件名,数据);
- Event.$on(事件名,data => {});
- $on监听自定义事件,因为有时不能确定何时触发事件,一般会在mounted或created钩子中来监听
- 父子组件通信
axios&&fetch:数据请求
-
axios 对已获得的数据进行了一层封装XSRF
- axios底层自动对数据进行了格式化
- axios参数根据get和post决定
- get请求 参数要通过data发送
- post请求 参数要通过 params发送
- 如果你直接使用npmjs.com官方文档,会有坑
- 解决步骤
-
- 先设置请求头
-
- URLSearchParams的构造器函数得到params对象
- 3.使用params对象身上的append方法进行数据的传参
-
-
fetch并没有进行封装,拿到就是格式化后的数据
- fetch进行了多一层的格式化
- res.json()
- res.blob()格式化二进制
- res.text()
- 1.fetch的get请求的参数是直接连接在url上的,我们可以使用Node.js提供的url或是querystring模块来将Object-->String
- fetch的请求返回值是promise对象,所以我们可以使用.then().catch(),但要记住.then()至少要写两个,第一个then是用来格式化数据的,第二个then是可以拿到格式化后的数据
- 格式化处理方式有
- fetch('./data.json') .then(res=>{ res.json() //res.text() res.blob() }) .then( data => console.log(data)) .catch( error => console.log( error ))
- fetch进行了多一层的格式化
过滤器
- 特点:
- 渲染格式化后的文本却不改变其本身内容
- 作用
- 文本数据格式化
- 全局过滤器 filter -须在vue实例声明前定义过滤器,否则会出现检测不到过滤器的情况
-
{{ dateStr | date }}
<div>{{ dateStr | date('YYYY-MM-DD hh:mm:ss') }}</div> - <script> Vue.filter('date', function(value, format) { // value 要过滤的字符串内容 // format 过滤器的参数 }) </script>- 局部过滤器 filters
- 局部过滤器是在某一个vue实例的内容创建的,只在当前实例中起作用
- { data: {}, // 通过filters 属性创建局部过滤器 filters: { filterName: function(value) {} } }
插槽
- 可以写任何模板代码
- 插槽用于决定将所携带的内容,插入到指定的某个位置,使得模块分块,具有模块化特质。
-
- 默认插槽
- 《slot> 标题 </slot》
-
- 具名插槽
- 顾名思义就是带名字的插槽
- 通过给组件中间的元素起名slot 可以在组件中通过name去找对应的插槽解析
-
- 作用域插槽
- 可以在组件内解析数据
- 在template元素上添加属性slot-scope
- 插槽中的内容不能访问父级作用域
生命周期
- 分为三个阶段,8个钩子函数
-
- beforeCreate:组件创建前:
- 作用:
- 为整个生命周期做准备工作,初始化实例的事件 和生命周期
- 意义:
- 数据拿不到
- 真实DOM拿不到
-
- Created:组件创建结束:
- 作用:
- 初始化Data数据
- 意义:
- 数据可以拿到
- 真实DOM拿不到
-
- beforeMount:组件挂载前:
- 即将挂载编译后的HTML到对应位置时触发的函数
- 内部完成事务:
-
- 先判断el选项-new Vue是否有el
- 有,继续判断是否有template选项,证明有子组件
- 有template,那么我们通过 render函数将jxs解析为VDOM对象模型
- 无template,那么我们需要通过outHTML手动渲染
- outHTML,元素外进行渲染,并且会代替原来的容器盒子,并且template在实例内会被解析,将来不会渲染到页面
- 无 那么我们需要手动挂载
- new Vue().$mount('#app')
-
- 意义:
- 数据可以拿到
- 真实DOM没有拿到
-
- Mounted:组件挂载结束:
- 这里是将编译好的HTML挂载到页面完成后执行的钩子函数,形成真实DOM(编译好的HTML替换vue实例上的el属性指向的DOM对象或替换对应的html标签里的内容)
- 作用:
- 发布HTML请求页面初始化需要的数据
- 注意:
- 这个函数在vue的整个生命周期中只会执行一次。如有页面数据的变化,会执行update函数来更新数据
- 意义:
- 数据可以拿到
- 真实DOM可以拿到
-
- beforeUpdate 组件更新前
- 作用:
- 这里会实时监听data数据变化,如有更新,那么会重新渲染vdom
- 意义:
- 数据可以拿到
- 真实DOM也可以拿到
-
- updated 组件更新结束
- 作用:
- VDOM重新渲染,然后通过render函数解析为VDOM对象模型,在通过Diff进行比对生成patch补丁对象,然后重新渲染为真实DOM
- 只改变变化的部分,其他部分不改
-
- beforeDestroy 组件销毁前
- 外部销毁
- 通过开关完成
- DOM被删除了
- 组件也被删除了
- 通过开关完成
- 8.destroy 组件销毁结束
- 内部销毁
- 通过调用$destroy()来完成
- DOM没有被删除
- 需手动删除
- 组件被删除了
- DOM没有被删除
- 通过调用$destroy()来完成
- 内部销毁
vue/cli[脚手架]
- 什么是cli?
- cli是vue提供的一个用来快速构建项目环境的一个工具,底层使用的是webpack
- 使用
- cli的安装
- npm换源:npm config set registry registry.npmjs.org。
- 使用淘宝镜像加速
- npm i @vue/cli -g//$yarn global add @vue/cli
- npm换源:npm config set registry registry.npmjs.org。
- 验证是否安装成功
- $ vue 看是否有东西输出,如果输出命令提示,证明安装成功
- 查看版本号:$vue --version
- vue create +项目名称
- 启动本地服务器:npm run serve// $yarn serve
- 生产模式下,把写好的内容进行编译打包,最后部署到服务器上
yarn build
- 查看当前项目默认的webpack配置信息
- $vue inspect
- 在当前项目中安装插件
- vue add [plugin]
- 以图形化界面创建和管理项目
- vue ui
- 修改默认的webpack配置
- 先创建vue.config.js 文件,在这个文件中修改相关配置
- cli的安装
分析目录
- node_modules 项目的依赖包
- cli3 webpack配置放在node_modules中
- public 静态资源目录( 生产环境 )【 这个目录下的静态资源不会被webpack 编译 】
- img
- js
- CSS
- favicon.ico 项目标题的logo
- index.html 根实例组件的模板,也是整个项目的容器
- src 源代码开发目录( 也是开发者主要开发的目录文件夹 )
- assets 开发环境的静态资源目录 ( 这个目录中的资源会被webpack编译)
- assets中如果图片的小小 < 4K 我们就将这个图片转化成 base64
- base64它是我们前端处理图片的一种形式,将图片路径进行编码,它可以减少一次ajax请求,达到前端性能优化的一个方案,但是base64有一个弊端,这个弊端就是会污染html结构
- components 组件存储目录
- xxx.vue文件 单文件组件 一个vue文件就是一个组件
- 组成部分:
- template模板 ( 必须写的 )
- script脚本 ( 可写可不写)
- style样式 ( 可写可不写 )
- scoped 作用是可以减少命名冲突,规定一个样式的作用域
- 组成部分:
- xxx.vue文件 单文件组件 一个vue文件就是一个组件
- assets 开发环境的静态资源目录 ( 这个目录中的资源会被webpack编译)
- gitignore git上传忽略文件配置
- babel.config.js 优雅降级配置文件 用来将es6 --> es5
- package.json 整个项目的依赖配置文件
- README.md 整个项目启动的说明性文件
- .browserslistrc 浏览器版本的支持
- postcss.config.js 项目css预处理的配置
- package.lock 整个项目的依赖性文件的信息
cli导入导出
- 它是 webpack + es6模块化来集中实现的
- es6模块化:
- 模块的定义 const obj = {} const fn = function(){}
- 模块的导出有两种形式
- export default //默认导出一个
- export // 批量导出,导出多个
- 模块的引入
- export default 导出 import xxx from '../xxx.xx'
- 如果是export 导出
- improt { xx } from '../xx.xx' || import * as xx from '../xx.xx'
- 特殊说明
- cli3 将webpack配置放在 node_modules,所以Vue并不希望大家去修改这部分webpack配置 如果我们将来需要更改webpack配置,那么我们需要在 项目 根目录 下创建一个 vue.config.js文件
vue-router
- 是构成 SPA( single page App )单页面应用 的关键技术
- 多页面应用 有多个html文件,通过a标签的连接联通各个页面
- 缺点:
- 开发起来太冗余,编译、压缩很耗时间
- 页面之间的跳转速度太慢,这个时候就会出现一个严重的问题,白屏
- 单页面应用
- 不需要刷新页面,因为它就是一个页面
- 这个页面内容在切换
- 单页面内容之间的切换要想实现我们就是用路由
- 如今我们的app、后台管理系统 主要的开发形式就是spa
- vue-router-基础:
- 1.vue 路由的mode(模式)有几种, 分别是什么?在那些环境下运行?
- 。 hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。 #/home
- history: 依赖 HTML5 History API 和服务器配置。【需要后端支持】 /home
- abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。【 这个模式不常用 】
- 总结:
- hash/history 常用于浏览器端,abstract用于服务端
- 1.vue 路由的mode(模式)有几种, 分别是什么?在那些环境下运行?
- 2.路由的使用步骤
- i. 安装 vue-router yarn add vue-router
- ii. 在src目录下创建一个router目录, 里面创建一个index.js文件 , 这个目录就是router的模块
- 安装stylus npm install stylus stylus-loader --save-dev
- iii. 引入第三方的依赖包, 并注册路由:
- 注意: import这个关键字要放在整个文件的上
- import Vue from 'vue'
- import VueRouter from 'vue-router'
- Vue.use( VueRouter ) //使用vue-router这个第三方插件
- 注意: import这个关键字要放在整个文件的上
- iv. 创建了一个router对象实例,并且创建路由表
- const routes = [
- {
- path: '/home',
- component: Home
- }//每一个对象就是一个路由
- ]
- const router = new VueRouter({ -routes//路由表 必写的
- })
- v. 导出router实例
- export default router{routes}
- vi. 入口文件main.js中引入路由实例 router , 然后在根实例中注册
- import router from './router/index.js'
- new Vue({
- router,
- render: (h) => App
- }).$mount('#app')
- vii.给路由一个路由展示区域
- 如果是以及路由, 那么我们放在App组件中,用一个 的组件表示
- 他是承载路由注册后组件的集合
- viii.当页面第一次的打开的时候, 需要做一个重定向, 就是要自动跳转到 /home 这个路由上
- const routes = [- { //我们要求这个路由的配置要放在路由表的最上方
- path: '/',
- redirect: '/home'
- } -]
- ix.业务: 错误路由匹配
- const routes = [
- {
- path: '/error',
- component: Error
- },
- { //这个就是错误路由匹配, vue规定这个必须放在最下面,它必须将上面的路由全找一遍,找不到才用当前这个
- path: '**',
- redirect: '/error'
- }
- ]
- x.vue路由模式的确定 mode
- i.如果你使用的是 hash , 那么a标签就可以了
- ii.如果你使用 history , 那么我们最好将a标签改成 router-link 这个组件
- router-link 这个组件 身上必须要有一个 to 属性
- 路由跳转:
- 放在App组件中 router-link to="/" exact>首页</router-link
- 路由跳转:
- router-link 这个组件身上加一个 keep-alive属性可以进行浏览器缓存
- xi.二级路由
- 注意: 写好配置之后,不要忘记了, 在对应的一级路由的组件中书写 路由展示区域:放在Shopcar组件中router-view></router-view
- const routes = [
- {
- path: '/shopcar',
- component: Shopcar,
- children: [
- {
- path: 'yyb', //不写 /
- component: Yyb
- }
- ] -}
- ]
- xii.命名路由
- 作用: 就是简写路径了
- 使用: 单项数据绑定to属性 -放在App组件中 router-link :to = "{name:'yyb'}"/>
- .{
- path: '/shopcar', -component: Shopcar, -//子路由 -children: [ -{
- path: 'yyb', // 容易犯错点 /yyb X
- component: Yyb,
- name: 'yyb' //命名路由
- },
- {
- path: 'junge',
- component: Junge
- }
- ]
- }
- vue路由-进阶 --> 动态路由
-
核心功能: - 路由传参 - 路由接参
-
动态路由:url中路由是改变的,但是改变路由公用一个组件 - export default new Router({
mode: "history", routes: [{ path: "/", component: Index, //配置子路由 children: [{ path: "a",//子路由的配置path不要加/ component: A }] }, { path: "/Login", components: { default: Login, a: A } }, { path: "/Datile", component: Datile }, { //动态路由 path: "/Datile:ids", component: B, children: [{ path: "a", componenet: A }, { path: "a/:xx", componenet: A }] } ] })
-
- 例子: