Vue学习笔记
- 数据绑定
- 脚手架Vue CLI
- 组件
- 组件化开发
- 需要安装的插件
- 自定义组件
- 定义自己的组件
- 使用自定义的组件
- 普通组件--局部注册
- 普通组件--全局注册
- 普通组件的局部注册和全局注册的区别
- 第三方组件Element-ui
- computed 计算属性
- 修改计算属性
- watch 侦听器
- 延时器防抖
- watch 的完整写法
- scoped样式冲突
- scoped原理(了解)
- 组件通信
- prop
- v-model原理
- .sync
- vue调试工具
- ref和refs
- 异步更新和$nextTick
- 路由
- 单页应用和多页应用的区别
- 路由的基本使用
- 组件存放目录问题
- 路由模块封装
- 实现导航高亮效果
- router-link
- 两个高亮类名的区别
- 自定义匹配的类名
- 声明式导航-跳转传参
- 查询参数传参
- 动态路由传参
- 两种传参方式的区别
- 动态路由可选参数
- 路由重定向
- 重定向
- 404
- 路由模式配置
- Vuex
- vuex的基本认识
- Vuex的基本使用
- 1.构建vuex多组件数据共享环境
- 2.构建一个空仓库
- 核心概念-state状态
- 辅助函数-mapState
- 不能直接修改仓库store内数据
- 核心概念-mutations
- 辅助函数-mapMutations(简写方法)
- 核心概念-actions
- 辅助函数-mapActions
- 核心概念-getters
- 辅助函数-mapGetters
- 核心概念-模块module
- vuex中从模块中访问state
- vuex中从模块中访问getters
- vuex中从模块中访问mutations
- vuex中从模块中访问actions
数据绑定
v-model是实现数据双向绑定,页面发生变化,name也会发生变化;name发生变化,页面也会发生变化
<input type='text' v-model="name">
:value
是实现单向绑定,name发生变化,页面就会发生变化;但是页面发生变化,name并不会发生变化
<input type='text' :value="name">
脚手架Vue CLI
在想要创建工程的目录里面输入下面内容,创建hello工程
vue create hello
选择第三个,手动选择。因为eslint暂时用不到
下一步,安空格取消掉Linter,然后按回车下一步
然后选择vue3
依赖存哪里去,一般选择package.json
是否要生成一个快照,用于后续快速创建项目
接下来就生成了vue工程
通过npm run serve运行
组件
组件化开发
需要安装的插件
装了插件才有高亮
自定义组件
定义自己的组件
在compoents目录下新建一个MyHello.vue
然后添加基本内容,定义组件名为MyHello
使用自定义的组件
接着执行npm run serve, 便可以发现组件生效了
普通组件–局部注册
局部注册,只写组件名也可以,是一种简写方法
创建一个新的vue,输入<v…选择第一个,就可以生成默认的模板
生成后的效果
使用流程:创建组件–导入–注册–使用
普通组件–全局注册
在多个界面都要使用的通用组件可以进行全局注册,这样全局都能使用了
全局组件在main.js中进行注册
在完成组件创建后,在main.js中导入,然后全局注册即可.
全局注册完成之后,在所有的组件范围内都可以使用
普通组件的局部注册和全局注册的区别
第三方组件Element-ui
computed 计算属性
比如下面篮球数量进行更新了,礼物总数也会自动重新计算
一般属性是放data里面,而计算属性要放computed里面,并写成函数的样子
computed与methods区别
特点是computed的缓存机制,只有依赖数据变化才会重新计算,数据不变情况下,即使网页刷新也不会重复计算的。性能比较高
修改计算属性
一般情况下,计算属性是不可修改的
如果想要修改计算属性,应该将computed中的函数写法,改写成类的写法,并要有get和set两个方法
如果要实现修改,需要在set里面对依赖数值进行修改,应该将’吕‘给this.firstName,把’小布’给this.lastName。
set的本质是修改了依赖数值,然后触发了get
watch 侦听器
注意:
在js中,方法名不能直接出现 点.
这种特殊字符的,需要加上引号
如’对象.属性名‘
延时器防抖
如果数据频繁变化,后台计算会比较频繁,因此可以设置延迟器。但这种情况下只会延迟执行,但是仍然都会执行;因此再次变化的时候可以删除延迟器,添加新的延迟器,进行重新计时。
这样就可以在变化停止时,进行更新。实现防抖的功能。
(与页面无关的数据,直接绑定在this对象里面,无需额外在data里面声明timer)
watch 的完整写法
比如除了监听obj中words还要监听语言,那么就要声明deep:true,监听对象obj里面的每个属性。
(如果直接监听两个,就太麻烦了,特别是数量是3个、4个…的时候)
但是handler只会在数据修改的时候才会触发,为了使得一进页面就修改一次,可以使用immediate:true
例子:
scoped样式冲突
如下图所示,这是组件的vue,只是想给BaseOne加上样式,但是所有的div都加上了样式
为了使得样式只作用于当前组件,就需要加上scoped
组件还是推荐加scoped的,因为组件应该有自己的样式,而不应该作用于全局
scoped原理(了解)
加上scoped,会给当前组件内所有元素,都添加一个哈希值,div
组件名改成了 div-哈希值
,因此不同组件内的div不会发生样式冲突了
组件通信
子组件给父组件通信$emit
父组件给子组件通信prop
prop
限制使用组件的人,防止他们乱传参数。
类型校验(比如下方的进度条应该传入一个数值,如果传入一个布尔值,那就应该出错)
可以通过写成对象的方式,进行更加详细的校验
如果想要修改prop值,需要子组件通知父组件去修改。直接修改prop会报错。
v-model原理
两条"<input" 语句是等价的
v-model还要仔细看
.sync
子组件要通知父组件修改的时候,需要 通过emit实现,并补上update:
字段
简单得说,加上.sync,相当于不用额外再去写触发事件了,子组件可以直接通过emit实现,是一种语法糖。
vue调试工具
参考链接
ref和refs
异步更新和$nextTick
在vue中,是要等这一段程序操作完才更新dom,这时候直接去获取焦点,是还没更新的,因此要异步去操作。
输入框获取焦点:就是光标闪烁在输入框
正确写法,$nextTick会等dom更新完后,再去获取焦点。
路由
单页应用和多页应用的区别
路由的基本使用
注意安装得时候Vue2 安装vueRouter3.x vuex3.x
Vue3安装vueRouter4.x vuex4.x
注入完成后,就能在url中看到/#/
的字符了
把用于显示的文件放在views目录里面
组件存放目录问题
路由模块封装
这样在main.js中只要import,以及在new Vue中加入router即可
把路由相关内容写在router/index.js里面。注意封装后,路径改变,要进行修改,否则找不到views。
但是每次移动文件位置都要改路径很麻烦,因此可以将相对路径改为绝对路径,其中@表示src目录(但不能直接写成src)
实现导航高亮效果
router-link
可以看到router-link本质还是a标签。会给选中的导航,添加router-link-active类
因此可以添加css样式,使得它高亮
两个高亮类名的区别
router-link-active模糊匹配:如果to=“/my"只要是/my开头的路径都能匹配到
router-link-exact-active精确匹配:如果to=”/my",只能匹配到/my
自定义匹配的类名
这样就能通过自定义的类名去设置样式(css)
声明式导航-跳转传参
查询参数传参
点击导航,就能进行跳转,url中也会携带参数。如key=黑马程序员
可以通过$route.query.key
来获取,在js中则需要this.$route.query.key
来获取
动态路由传参
配置导航的时候可以直接用/
,而不是用 ?参数名=值
这种形式了。
动态路由配置的时候是words,可以获取参数就用$route.params.words
因此动态路由传参分为三步
1.配置动态规则 2.配导航连接 3.参数获取
两种传参方式的区别
动态路由可选参数
在配置路由规则的时候,参数后面添加个?就行了
加上?后,搜索页这样也能展示成功了。
路由重定向
重定向
404
路由匹配规则会从上往下依次匹配,如果发现前面三个都没匹配到,就会被path:'*'
匹配到,就会重定向至模块NotFind
路由模式配置
Vuex
vuex的基本认识
Vuex的基本使用
1.构建vuex多组件数据共享环境
Son1组件里面只是丢了个标签和没有逻辑的button,Son2也是一样的。
在根组件里使用Son1和Son2。
这样多组件数据共享的环境的就搭建好了,接下去考虑如何同步三个组件的数据?
2.构建一个空仓库
如在用VueCli构建时,勾选了vuex就不需要额外安装了。
注意233和344口诀,vue2安装router3和vuex3;vue3安装router4和vuex4
首先在@store/index.js里面,写vuex的核心代码
包括插件安装、创建仓库、导出store给main.js
在main.js中,挂载到Vue对象当中
使用时:可以直接通过this.$store
访问到store对象
核心概念-state状态
例子:
提供数据
模板中通过{{$store.state.参数名}}
去使用
组件逻辑中通过this.$store.state.参数名
来进行访问
在js模块中可以通过store.state.参数名
来进行访问
辅助函数-mapState
一种简写方式,底层还是从$store.state.参数名
去读取
由于直接使用this.$store.state.count
实在太长了,于是可以用计算属性使得,变量的长度得以减小,这样就可以直接使用count
了。但是每次这样写计算属性太麻烦。
于是可以在计算属性里面直接加入mapState(['count'])
,相当于count(){return ...}
这么一大段,以达到简写的效果。可以通过逗号间隔,引入更多状态。
注意要展开运算符映射。就是要加三个点: ...mapState(['count'])
,不然的话就是mapState
占满整个计算属性,就没法添加别的了。
导入mapState后可以直接使用,但这种一般不会这么用
而是给他放入计算属性里面去使用
因此使用组件中可以直接使用该状态,而不必$store.state.count
…
不能直接修改仓库store内数据
由于vuex遵循单向数据流,组件不能直接修改仓库的数据,因此要通过mutations通知仓库去修改
由于this.$store.state.count++
是错误写法,检测会影响性能(即便能修改,也是不规范的,一定要遵循单向数据流),因此可以设置strict:true
为严格模式,这种模式下出现这种写法会直接报错(有利于初学者检测不规范代码)。注意:但是在最终上线的时候,是不需要开启这个模式的。
核心概念-mutations
把操作state里面数据的方法,写在mutations里面。
在组件中使用,直接调用mutations,来修改state里面的数据
注意mutations里面的方法,第一参数一定要是state
这时候可以通过调用this.$store.commit("addCount")
,来修改count值
mutations中的方法同样可以传递参数
注意只能传递一个参数,如果非要传递多个参数,可以写成,对象、数组形式。
比如下面,mutations方法中即便定义了str形参,也是接不到这个字符串的。
因此可以用下面的方式
例子:
下面例子中,$store.state.count已用计算属性简写了。如何让他和输入框input进行双向绑定?
众所周知v-model是双向绑定,但是他会直接修改仓库内的数据,不符合单向数据流,那该如何解决呢?
v-model是 :value和@input的简写,写了:value就可以将数据映射到输入框,当输入框输入内容,就可以通过@input事件来触发函数,以此来调用mutations方法,来修改仓库数据
触发的函数,调用mutations方法
辅助函数-mapMutations(简写方法)
mapState是将store中state的数据映射到computed计算属性中,组件中可以直接使用该计算属性
mapMutations是将store中mutations的方法映射到methods方法中,组件中可以直接调用该方法
核心概念-actions
mutations必须是执行操作时同步的,而如果要处理异步数据,就要写在actions里面。
调用则通过dispatch
来调用
actions相当于包装一下,把异步处理掉了,再去执行mutations。
其中,context表示上下文(此处未分模块,可以当成store仓库,可以调用里面的commit来执行mutations)
辅助函数-mapActions
写法
核心概念-getters
从state中派生出一些状态,这些状态依赖state的,此时会用到getters。
比如state发生了变化,getters内相应的数据也会同步发生变化
辅助函数-mapGetters
映射到计算属性中
核心概念-模块module
当store中有很多状态时,将变得很臃肿。分模块可以让项目变得易于维护
模块js文件放在目录store/modules下面
将state,mutations,actions,getters都export
加载模块时的写法也要更改。其实modules:{user} 本质上就时{state,mutations,actions,getters}
注意store/index.js 要写上引入的模块。
为什么叫index.js其实也能理解了,他作为根模块root,可以去引入其他模块。
将整个{state,mutations,actions,getters}对象,放入new Vuex.store({})里面即可。
其实就是将两个子模块挂在根模块root下面。
vuex中从模块中访问state
分模块可以让每个模块内容写在单独的js里面,更加易于维护。
但本质上,还是单一状态树。打开state发现,两个子模块还是挂在根级别的state中
要访问模块中的状态有两种方法,第一种是纯原生,第二种是映射。注意映射的时候,模块要开启命名空间namespaced:true
原生方法
下述,user是模块,name是userinfo对象中的元素,userinfo是放在user模块的state里面的。
访问的只要$store.state.模块名.xxx
即可,不需要加多层state,因此vuex本质上还是单一状态树,
会将子模块的state挂在根模块的state里面。
映射方法
1.直接将模块名进行mapState映射,那么拿到的就是模块内所有的state数据。
如果要取值的话,那么就从模块名为起点,从多级目录下去取。
2.基于子模块去映射
通过mapState('模块名',['xxx'])
的方式去映射。注意这种情况下,模块一定要开启namespaced:true
这样就能直接使用子模块中的数据了。
注意:上述两个mapState不会冲突,只要计算属性名不相同即可。
vue调试工具中,如果没看到namespaced的话,应该是配置错误了。
vuex中从模块中访问getters
基本上与访问模块中的state是相同的。
除了直接通过模块名访问,这个写法要通过中括号的方式。
通过原生方法去获取数据
为什么要用中括号,变了花样呢?
通过打印发现,有个值为user/UpperCaseName,由于有特殊字符,因此无法直接通过点.
来实现,要用中括号
为了方便书写,建议通过子模块映射,这样可以直接获取数据
vuex中从模块中访问mutations
为了不将mutations和actions挂载到全局,需要开启命名空间