Vue是一套用于构建用户界面的渐进式Javascript框架,给它数据它就变成界面
Vue特点:
- 组件化模式
- 声明式编码,无需操作dom
- 使用虚拟dom和diff算法,尽量复用dom节点,例如对于新数据是采用添加而不是整体修改替换
简单vue实例:先创建html容器,再创建vue实例,绑定容器,实例中el绑定,data存储容器数据(便于替换)容器也叫做vue模板
容器和实例之间,只能是相互一对一的关系
一、模板语法
插值语法
同上Hello实例里,data里的数据插入替换到容器里的{{ }}中,{{ }}里是js表达式就可以
指令语法
如果不加v-bind,href没法识别出url里的内容,而是只简单的把它当成一个字符串“url”,且v-bind可以简写为一个冒号
多层级:
二者区别:
标签体指的是<h1> </h1>之间的内容,插值语法用于改变标签体内容,指令语法多为执行和解析标签的属性
二、数据绑定
v-bind(单向数据绑定)
利用v-bind把输入框的value属性定为“尚硅谷123”,如果在页面输入框中修改值,data里的value不会改变
v-model(双向数据绑定)
只能用在表单类输入中
三、el和data的两种写法
el
第一种是常规:
第二种:可以用在定时把容器和实例绑定
const v = new Vue()
data
对象式:常规
函数式: 用于组件,不能写箭头函数(因为调用会变成window而不是vue)
或者这样写
四、MVVM模型
举例:一般用vm来命名实例对象
五、数据代理
回顾Object.defineProperty
参数是“要定义的属性对象” “要定义或修改的属性名称” “要定义或修改的属性描述符”,返回值是被传递给函数的对象
通过defineProperty给person对象增加属性age
数据代理
通过一个对象代理对另一个对象中属性的操作(读写)
通过obj可以操作x,通过obj2也可以操作x
在vue中使用数据代理
那两条线就是数据代理
下划线data就是data,只不过做了小小修改多了一些处理
简单来说数据代理是底层原理
六、事件处理
事件基本使用
v-on(当这个事件发生的时候),一般简写成@
当click事件发生后,调用showInfo的回调函数,函数要写在methods中
所有被vue管理的函数都不要写成箭头函数,因为箭头函数会向外找"this",而这个this是window
传参:加了括号就可以传参,参数顺序要对应,如果没有$event占位的话,函数的事件event就会丢了也无法console.log(event.target)
函数也可以写在data而不写在methods中,但是函数本不需要数据代理,但是放进data里又进行了数据代理,会让vue负载很重,所以应该写在methods中
事件修饰符
修饰符可以连续写,比如click.prevent.stop
加在click后就行
捕获阶段:由外往内
冒泡阶段:由内往外
如果不加passive,页面会先执行函数才滚动(造成卡顿),加了之后无需等待函数执行就可以滚动
键盘事件
keydown:按下之后不用等弹起来就出发
keyup:按下去弹起来才触发
例如下面例子:输出input框中的内容,由于输入一个就会输出一次,所以改成@keyup.enter就可以在按下回车的时候才输出
按键别名:
tab键特殊,必须搭配keydown使用
七、计算属性
一个例子说明计算属性的重要性:实现输入框分别输入姓和名,全名把它们拼接起来
- 首先用插值语法实现:会存在问题如果需求多了{{}}中会有很长表达式,违背了vue提倡简介表达式风格
- methods实现:
- 计算属性:
当有人读取计算属性时,计算属性中的get就会被调用,并且get函数返回值就作为计算属性的值
计算属性的简写:确定只读不改才能使用简写
把它写成函数的形式
八、监视属性
例子:点击按钮切换天气
如果很明确监视的对象,则用上方写法,如果不明确,采用vm.$watch
深度监视
监视多级结构中某个属性的变化,不能只写numbers.a,而要加引号
监视多级属性中所有属性的变化,加deep:true属性就可以
监视简写形式
当配置项里只有handler时就可以简写(没有deep也没有immediate)
把监视的对象写成函数名替代handler
计算属性与监视属性对比
把计算属性的案例用watch写:
得先把结果fullname准备好,监视姓和名的变化
但是如果想过段时间后再获得结果,就要用watch
在watch中使用定时器要用箭头,因为用箭头,函数才没有this才会往外找this,才会找到vue
九、绑定样式
绑定class样式
绑定style样式
里面要写正确的样式
也可以用数组对象
十、条件渲染
v-show
false就不显示
v-if
十一、列表渲染
v-for
在persons数组中用p和index遍历,最好要写key,让每一个对象都有唯一的索引值
key的作用与原理
key给节点作为标识
列表过滤
v-modle收集input框中用户的输入,赋值给keyword
用computed属性:
用watch属性:用filter函数
列表排序
在过滤好的前提下进行排序,采用sort函数
监视数据的原理
新增属性:利用Vue.set
!!!
修改数组中的某个元素不能是例如=
{.......,.....,},而应该是
这样才奏效,因为数组对象没有setter,属性值有setter
十二、收集表单数据
利用v-model,默认收集输入框的value值,对于单选框也要配置value值收集。对于多选框也要为每个选项配置value值,对于勾选框无需配置收集到的是true或者false
十三、过滤器
效果:
bootCDN免费开源
用filter属性配置:
把time的数据通过管道符传到后面过滤器
过滤器是局部的,其他的vue实例不能用
十四、内置指令
v-text
与插值语法作用相同
v-html
v-cloak
v-once
一次性,初始化的n值不会随着按钮改变
v-pre
vue不去解析有v-pre的语句
十五、自定义指令
函数式
定义一个v-big指令,和v-text类似,但是会把绑定的数值放大十倍
把需要定义的指令放在directives属性中
形参element是操作的dom元素,形参binding是绑定对象(v-big后接的)
对象式
定义一个v-fbind指令,和v-bind功能类似,但是可以让其所绑定的input元素默认获取焦点
十六、生命周期
例如mounted
挂载流程:
template作用:占位符
十七、非单文件组件
模块化:js按照模块化的标准拆分成好几个js
非单文件组件:一个文件中有n个组件
单文件组件:一个文件中只包含有一个组件
基本使用
创建组件:组件定义时不写el,而且data要写成函数式
注册组件:在vue实例中定义components属性,也是key:value值,key是组件真正的名字,value是创建组件时的临时变量
编写组件标签:
关于组件起名的注意点:
组件的嵌套
蓝色组件里还有两个橙色组件,叫做上下级关系,也是嵌套
在school组件里嵌套student组件,即在school中定义components,不过需要注意的是student的定义要写在school的前面,否则会报错
而在使用中,student不能写在school外面
而应该:在school的template中被定义
组件的结构:vm领导app组件,app组件领导所有的组件
所以可以定义app组件,把所有组件写进来,但是不需要写student,因为student已经被school领导了
而在vm中的components中只需要写app即可
在html结构中也只用写app标签即可
VueComponent
一个重要的内置关系
十八、单文件组件
以.vue后缀结尾的文件,没法直接运行,需要变成.js,要么利用webpack要么利用脚手架
vue里写的东西:(注意注释的写法)
e.g.:要把模块化暴露,采用export default默认暴露,用name属性起名
还需要创建app.vue,汇总领导student和school组件,用import引入,在脚手架中可以使用<school>等组件标签
然后用一个main.js把app.vue引入
要么在html里引入<app>标签,要么在上面main.js中的new Vue中写入template:<app>
创建脚手架
npm install -g @vue-cli创建好了之后(用淘宝镜像),在相应父目录下vue create 项目名,创建成功后会提示npm run serve,开启了端口要是想结束ctrl+c就可以
文件结构:src里有assets放静态资源,components放组件,main.js不能修改
render函数
如果引入的是一个残缺版的vue,需要填充内容,然后template没法使用的时候,就用render函数补齐内容,render函数必须要有返回值,参数可以是createElement这个函数(用来创建内容比如h1标签)
ref属性
Vue的核心是不去直接操作dom,但是有时候又需要操作dom,这时候就需要ref属性,用this.$refs的属性
props配置项(组件的复用)
在组件中,把需要复用的属性从data中移出,放进props属性中,表明接收传过来的数据,(是可以传函数的!!!)
接收的方式有三种:
传值的方式:例如App.vue中,组件传值
props比data的优先级更高
mixin混入
如果几个组件之间有共同的东西,那么就把它整合起来,就叫混入,两个组件共享一个配置
创建一个minxin.js,把共同的东西写进去
如何调用混合呢?import引入混合,然后mixins配置项
全局混入再main.js中写Vue.mixin
插件
定义一个plugin.js作为插件,在main.js中用Vue.use(插件名)引用
plugins插件中定义install方法,里面写插件的各种方法
Vue.prototype是定义一个原型的方法,后续在methods中就可以直接this.hello()调用
scoped样式
加上scoped表示用的css范围是这个组件内
可以指定使用less或者css
自定义事件(子组件给父组件传东西)
绑定
v-on:事件=" 操作 "
子组件给父组件传东西:通过父组件给子组件绑定一个自定义事件
解绑
解绑一个事件:
解绑多个事件:
全局事件总线(任意组件间的通信)
这个x就是所谓的bus
消息订阅与发布(任意组件之间通信)
安装库npm i pubsub-js
在接收数据的组件引入库,pubsub是一个对象,然后在组件挂载完毕的时候订阅消息并写回调函数
回调函数参数:第一个是消息名,第二个是要传的数据
在发布消息的组件引入库,然后在methods中发布消息
十八、浏览器本地存储
例如打开唯品会网页,没有登陆,但是搜索了商品,然后历史记录里有搜索的记录,这个记录存在本地硬盘里。利用windows内置localStorage的函数,例如setItem,getItem等
十九、nextTick
$nextTick指定的节点会在dom更新解析模板完毕后再执行,因为vue在执行语法的时候是先把所有逻辑方法执行了再重新解析模板,但有时候我们又需要解析模板后再执行逻辑方法,所以nextTick用的特别多
二十、动画效果
引入第三方库animate.css,npm install animate.css
使用:appear是一进入就要有动画,然后下面三个是配置属性
二十一、配置代理
使用axios,引入库npm i axios
然后引入库import axios from 'axios'
axios写法:
出现跨源请求的问题,有cors、jsonp和代理服务器的方法解决。cors是服务器返回响应的时候携带响应头(后端),容易造成任何人都能拿到数据;jsonp利用script标签解决,前后端一起配合才行,而且只能解决get的跨域而不能解决post的。所以利用代理服务器解决。
代理服务器端口号和前端相同,所以不存在跨域,和后端也不存在跨域,因为两台服务器之间不用XMLHttpRequest发起请求(nodejs里没有),而用传统的http,所以也不存在跨域。
开启代理服务器的方式:nginx和vue-cli
利用vue-cli开启:在vue.config.js中写入devServer配置项,端口号(!!!)写后端的号而不是8080
此时前端请求的时候端口号应该写8080,且写明白请求的资源页面数据(students)
如果请求的资源前端已经有了,就无需将请求通过代理服务器又转发给后端,前端直接给资源
这种方式只能配置一个代理,而不能多个
所以能开启多个代理服务器的方法:
pathRewrite是为了路径重写,因为请求的时候需要服务器掠过前缀(否则找不到资源),所以要用空格代替前缀名
发起axios请求的时候要加入服务器前缀
请求带参数
二十二、vue-resource
vue-resource属于插件库,需要安装引入npm i vue-resource,引入也是Vue.use引入,它是vue的发起请求的库
使用方法和axios一模一样,只不过把axios变成this.$http
二十三、slot插槽
默认插槽
在组件里用<slot>标签表示可以插入东西
在引用组件的时候就可以在相应位置写入文字、视频、图片等
具名插槽(具有名字的插槽)
如果写了两个<slot>,它不是一个图片占一个slot然后另一个图片占第二个slot,而是两个图片占一个slot,且会出现两次
解决这个的办法是给每个插槽起名字
然后给使用插槽的元素加slot属性标记它要放到哪个插槽去
如果觉得每个元素都要写slot属性很繁琐,可以使用一个大div包裹起来在div上加slot,但是更好的是用template,在template上加slot,可以减小占位
作用域插槽
之前的插槽是App.vue把数据传给组件,作用域插槽是数据存在组件的data里并把数据传给App组件
组件里:
App组件里:
二十四、vuex
vuex是一个插件,利用npm i vuex@3安装(npm i vuex默认安装的只能在vue3中使用)
原来的共享数据方式(全局事件总线),BCD都想要A的数据,或者BCD都想修改A的数据,如果组件一多就很麻烦
而如果使用vuex,vuex不属于任何一个组件,连App组件都不属于,所以当多个组件依赖同一个数据,或者来自不同组件的行为需要变更同一个数据的时候,就要使用vuex
工作原理:Action和mutations和state都是对象,它们都由store领导,而如果组件想要利用vuex就要让store看得见
当vuex被引入vm和vc身上就有$store
创建文件目录,用于创建vuex中最为核心的store
在main.js中引入store,无需Vue.use(Vuex)
而在store中引入Vue和Vuex,因为如果不这样而是在main.js中写,它会报错,即使调整import和Vue.use的前后顺序也无济于事,因为代码会先执行完所有的import才会执行Vue.use
举例(要结合原理图看)
在组件的方法里,组件要给vuex处理数据,就要dispatch(发送)将处理函数的名字和参数给atcion,也可以掠过action,直接commit传给mutation,这种情况是没有逻辑判断只有数据操作。
action中写业务逻辑,比如判断与发起网络请求之类的,然后顺着原理图通过commit递交给mutations,context参数是有点类似于mini的store对象,value是传的参数值
在mutations中只写数据的操作,例如加减乘除,参数是state数据和value值
在state中存共享的数据
store配置项getters
getters和actions,mutations,state一样也是对象,和它们同级
用于对state的数据进行复杂的加工,它可以把state获得作为参数,如果要在插值语法中使用的话
就store.getters的配置项中去找
mapState和mapGetters
在插值语法中一直要调用store.state来获得数据很麻烦,我们希望直接通过sum、bigSum等直接获取数据
mapState叫映射状态,用来处理上述问题
mapAtcions和mapMutations
多组件共享数据
数组里每一个字符串的名字都是state里有的data名,实现一个名两个用
模块化编码
把actions,mutations,state,getters分成实现哪个功能的模块,然后分开
然后在store暴露中,写入modules对象,并给模块起别名,在定义模块的时候要注意加配置项namespaced:true,这样暴露的时候别名才会生效
在使用数据和方法时也要按照分类
如果不使用map的写法,而使用基本的$store,就要注意加上模块的别名
二十五、路由
路由就是一组key--value的关系
多页面应用就是多个html相互调整,单页面跳转就是实现只有一个html,路由就是实现单页面应用(SPA应用)
路由分类:
基本路由
安装路由npm i vue-router@3,同样也是有版本限制
同样也有文件结构,创建router文件夹,然后写Js
index.js专门用来配置总的路由器
用<router-link>来指定路由链接,active-class选中谁谁就高亮,to属性指向组件名
用<router-view>指定组件的呈现位置
在切换组件的时候,组件是被频繁的挂载和销毁的
一般组件和路由组件的区别:路由组件靠路由匹配渲染出来,一般组件要组件引入并调用组件标签
嵌套(多级)路由
二级路由用children配置项,且路径不用加斜杠/,因为底层已经自动加过了再加就是多余
写多级路由的时候要把一级路由带上
路由传参
点击消息下方出现详细信息,则把详细信息作为一个新的路由组件Detail,放在Message下,而Message要传消息到Detail,如果用组件的通信就会很麻烦要写很多<Detail/>,所以采用路由传参
query参数
字符串写法要用模板字符串
命名路由
加name的配置项即可
跳转路由也不需要写一长串path,而是写name就可以
params参数
同样也可以携带参数传递
路由的props配置
也是为了让路由接收参数
路由的props和组件的props不相同
在总的路由配置中写要传的参数,有两种写法,第一种不推荐,因为传的值是死的
router-link的replace属性
浏览记录是一个栈,如果是push模式,它会一条一条追加到栈顶指针也指向栈顶,可以回退和前进。而replace是替换,不能回退与前进。默认是push模式
编程式路由导航
不借助router-link的就是编程式导航
缓存路由组件
当News和Message互相切换的时候,输入框的内容就会不见,原因是路由组件会伴随着切换不断挂载和销毁
因为News和Message都在Home中,所以在Home路由组件里我们需要把News组件缓存,写在keep-alive中,但是我们没必要把Message也缓存,所以Include里只用有News即可(写组件名)
缓存多个路由组件:
路由组件独有的生命周期钩子
activated激活 deactivated失活
比如News组件被切走就是失活,切回来就是激活
路由守卫
保护路由安全(权限),比如校验身份才能点击查看这个组件
全局前置
将路由先不暴露,在暴露之前定义路由守卫,路由守卫beforeEach的参数:to表示要切到哪个组件,from表示从哪里切换而来,next表示放行
加一些条件,满足条件才可以放行(调用next()函数)
如果有很多项需要判断if里面就很冗杂,可以利用路由的配置项meta(路由元)自定义该组件是否需要判断放行,
全局后置
如果 要切换后修改网页的title,要在后置守卫,切换后做。后置守卫没有next
独享路由守卫
只对单独一个路由组件设置守卫,利用beforeEnter。只有前置没有后置
组件内路由守卫
组件内路由守卫不是写在路由配置index.js里的,而是写在组件里
路由的history和hash模式
路由器默认开启hash模式
项目上线,需要打包,不再使用npm run serve,而是npm run build进行生产环境的构建。打包会自动生成dist文件夹,部署在服务器上。
利用node和express部署服务器
第一步新建文件夹,npm init
第二步npm i express
第三步构建好之后,新建server.js
下图是一个微型服务器,利用node server启动
二十六、UI组件库(ElementUI)
npm i element-ui安装
如果这样使用的话就会引入所有的组件,造成文件太大,而实际中我们只用到几个
所以只需要引入部分组件,详细参考官方文档
附录(说明自己的注意事项)
在实际上手操作中:
- 出现coponents name should always......时,把import的文件的vue后缀去掉即可
- 出现already included file name时,添加配置项即可
子组件给APP组件传东西的方法:App构造一个函数,把函数传给子组件(利用v-bind),然后子组件在props中调用这个函数,就能把参数传给App了
- ...对象的意思是把这个对象展开并入新对象