Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
Vue是个MVVM框架,使用了模块化+虚拟DOM
MVVM:Model-View-ViewModel ,核心是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监听和数据绑定
笔记:前端笔记
Title
Java
{{ message }}
Vue对象7个常用属性:
指令带有前缀v,代表他们是Vue提供的特殊特征
v-if
,v-else
,v-else-if
,根据表达式的真假切换元素的显示和隐藏(操作DOM元素,直接把DOM元素移除了)
yes
No
A
B
C
v-for
{{item}} ---> {{index}}
v-bind
设置元素是属性, 冒号后面代表属性名 v-bind:属性名=表达式
简写:
图片
v-on
绑定事件,监听DOM事件
v-on:都是相同的,所以可以简写:
v-on
还可以传递参数,事件修饰符等
事件修饰符
.prevent
阻止标签的默认行为.stop
阻止事件的冒泡.once
事件只触发一次
还有audio标签里面的play(播放) pause(暂停) 事件等
v-model
获取和设置表单元素的值!!
v-model
在表单是input,textarea,select…元素上创建双向数据绑定,会根据控件类型自动选取正确的方式来更新元素
v-model
会忽略所有表单元素的value,checked,selected特性的初始值而总是将Vue实例的数据作为数据源,你应该在JavaScrip在组件date中设置初始值!!!
修饰符:v-model.lazy
v-model.number
v-model.trim
你输入的文本是:{{message}}
性别: 男 女
你选中的性别的:{{str}}爱好:你选中的爱好是:{{temp}}
v-show
根据表达式的真假切换元素的显示和隐藏(和v-if效果一样,但这个v-show是操作disabled属性,DOM元素始终都在)
频繁切换建议使用v-show
,因为频繁操作DOM消耗大。
=18"/>
v-test
设置标签的文本值。例如 ,缺点会全部替换掉。解决:可以使用
{{ }}
语法
v-html
设置标签的innerHTML,可能会有XSS攻击
v-cloak
没有值,配合css可以防止vue介入慢,而引起的页面闪烁
v-once
没有值,在初始动态渲染后,都视为静态内容了
v-pre
没有值,跳过所在结点的编译过程(可以利用它跳过没有使用指令差值语法的结点,加快编译)
ref
属性,这个可以简洁操作DOM(id的替代者。如果写在组件标签上,则拿到的是ref属性所在标签对应子组件的实例对象)
directives
,注意:自定义函数里面的this不是vm了,而是window!!
组件:是可复用Vue实例,就是可以重复使用的模板(局部功能代码和资源的集合)
简单的:
动态数据:
(注册的时候是什么名,标签里面用就得用什么名)
new Vue({el: "#app", // 局部注册只能在这个根实例中使用components: {'my-com-a': { // 横线命名要加单引号template: `{{ title }}
`,data() { // data: function{}== data(){}后面是ES6的写法。写成方法是为了多个组件实例数据不相互影响return { title: '我是标题A' }}},MyComB: { // 这样可以不用加单引号,html中使用时会自动映射为上面那种命名template: `{{ title }}
`,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,}
});
父组件向子组件传值⭐
通过props选项接受父组件的传值
父组件
传递静态的值 动态绑定,绑定静态字符串值需要加单引号 msg父组件中data的值
props是只读的,如果强转修改Vue有警告。父子组件的所有prop都是单向向下绑定的!!
如果真的想要改的话,请复制一份到data中,然后再去修改data中的数据。(因为先接受props,再去加载data)
子组件向父组件传值
通过自定义事件实现⭐
绑定自定义事件:
第一种方式,在父组件中,
第二种方式,在父组件中,this.$refs.demo.$on('事件名',回调方法)
注意第二种方式,绑定自定义事件时,回调函数要么配置在methods
中,要么用箭头函数,否则this指向会出问题
触发自定义事件:在子组件中,this.$emit('事件名',数据)
解绑自定义事件:this.$off('事件名')
购物车
总数为: {{totalCount}}
非父子组件传值
通过父组件进行数据的中转 (兄弟组件)
如果只有一层的话使用父组件进行中转很简单,如果组件层数很多的话,将会变得非常繁琐!不建议
全局事件总线 ⭐: 独立的事件中心,用于管理不同组件间的传值操作 ,任意两个组件都可以通信,开发中用的最多。
安装全局事件总线:
// 标准的写法,在src/main.js中:
// 在其他组件中直接this.$eventBus.$emit(),this.$eventBus.$on(),所有的组件实例对象,即vc,vm都能看到!!
new Vue({el: '#app',render: h => h(App),beforeCreate() {// 安装全局事件总线(往Vue的原型对象上放的,所有的组件实例对象都有),this就是根vmVue.prototype.$eventBus = this; }
})
使用事件总线(最好用完在beforeDestory
钩子中,解绑当前组件所用到的事件!):
购物车
组件配置中,data,methods,watch中的函数…它们的this都是VueComponent实例对象
Test.vue
:(表示一个独立的组件,一般是MyTest用单词首字母都大写的这种命名)
TEST {{msg}}
App.vue
:(App一般是根组件,一人之上万人之下,管理所有的子组件)
vm -> App.vue -> Student.vue -> Person.vue..-> School.vue -> ...
哈哈
main.js
,人口文件(创建vm)
import App from './App.vue'new Vue({el: "#root", // 指定为哪个容器服务template: ` `, // 这个不写也行,或者在下面的id为root的div中写 ,或者render: h => h(App)components: {App} // 只注册APP主组件即可,因为App管理所有的子组件
})
⭐在脚手架中,自动引入的vue是残缺版的vue,即
vue.runtime.esm.js
,里面没有模板解析器,因为最终使用webpack打包发布的时候已经解析过了,就不应该有模板解析器了(体积不小),只能用这个方式:render: h => h(App)
,而用template:
会报错。因为
vue.runtime.xxx.js
,没有模板解析器,所以不能使用template配置项(template属性),需要rander函数接收到的createElement函数去指定内容。(而vue文件里面的template标签里内容是由一个专门的独立模块vue-template-complier
解析的,这个脚手架帮已经我们引入了
index.html
(单页面应用,就这一共html)
Title
vue单文件开发,js模块化开发需要在脚手架环境下才能执行。
多个组件共享的配置可以抽取出来一个混合对象。例如:
export const hunhe = { data(){...}, methods: {...} }
。局部:
{ mixin: [hunhe] }
, 全局:Vue.mixin(hunhe)
this.$nextTick(function() {})
指定的回调方法会在Dom元素更新完毕后再去执行!!一般用于当数据修改后,要基于更新后新的DOM进行某些操作时,要在nextTick所指定的回调方法中执行。
在Vue中我们可以使用
元素作为承载分发内容的出口,称为插槽,可以应用在组合组件的场景中。
以前我们是使用props
进行传递,不太繁琐,但也不算简单,使用插槽更简单一点。
不使用插槽中间的内容会被抛弃,使用插槽的话中间写的内容会替换组件中的slot标签
slot
中可以设置默认值,
,父组件中如果设置了插槽内容会被替换掉!
(挖个坑,等着组件的使用者进行填充)
实例文本 苏瞳
这里是父组件的视图模板,只能使用父组件的数据!!(因为这部分是父组件来渲染的){{ parValue }}
多个位置需要设置插槽,需要给slot
设置name
组件头部内容
内容1
内容2
组件尾部
作用域插槽:用于让插槽可以使用子组件中的数据
组件将需要被插槽使用的数据通过v-bind
绑定给
,这种用于给插槽传递数据的属性称为插槽prop
组件绑定数据后,插槽中需要使用v-slot
接受数据
(数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定)
{{ dataObj.value }} {{ dataObj.num }} {{ dataObj.value }}{{ dataObj.num }} {{ num }}
适用于多个组件进行频繁切换的处理,例如选项卡操作
用于将一个元组件渲染为动态组件,以is
属性值决定渲染那个组件。类似v-if
,v-else-if
的结构。
is属性在每次进行切换时,Vue都会创建一个新的组件实例 (组件的状态无法进行保留)
// 下面三个组件进行切换时,前一个输入框的内容就会消失!! var ComA = { template: `
A组件内容,` } var ComB = { template: `B组件内容,` } var ComC = { template: `C组件内容,` }
用于保留组件状态或避免组件重新渲染。
使用很简单:
include
属性,可以知道哪些组件进行保留状态,哪些不保留!!
在Vue插入,更新,移除DOM时,提供多种不同的方式的应用过渡动画效果。
,
标签
哈哈哈哈
Axios是一个开源的可以用在浏览器端和NodeJS的异步通信框架,主要作用的实现AJAx异步通信,体积小
特点:
XMLHttpRequests
http
请求Promise
APIXSRF
Vue.js
由于是视图层框架,所以不支持AJAX
的通信功能,为了解决,单独开发了一个vue-resource
的插件,但这个进入2.0后就停止了改插件对的维护并**推荐了Axios
框架,少用JQuery
,**因为操作DOM太繁琐!!
安装:
npm install axios --save
data.json
{"name":"苏瞳java","url": "http://baidu.com","address": {"street": "含光门","city":"陕西西安","country": "中国"}
}
test.html
test02.html
{{ joke }}
get/delete请求:
第一个参数:url,第三个参数:config
这里最好使用箭头函数,这样this才是组件实例对象
// 向给定ID的用户发起请求
axios.get('/user?id=12345').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]])
自己开发情况下会出现跨域问题,解决:
cors
后端设置响应头(使用多)
jsonp
利用的src属性引用外部资源不受同源策略(协议,主机号,端口号三者相同)的限制,但是只能解决get请求跨域的问题, 前后端配合。(使用极少)
代理服务器⭐(nginx,vue-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: ''}}}
}
/*changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080changeOrigin默认值为true
*/// 请求:发起axios请求 (不加请求前缀则请求本服务器中的资源)
axios.get('http://localhost:8080/sutong/students').then(reponse => {})
能够将计算结果缓存起来的属性(将行为转化成了静态的属性)。把data中的属性经过计算再去使用,但相对于方法有缓存机制。
全名(方法):{{fullName1()}}全名(计算属性):{{fullName2}}
调用发放每次都要计算,都有开销,那这个结果是不经常变化的呢?此时就可以考将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的特性就是将不经常变化的的计算结果进行缓存,以节约我们的系统开销
什么使用更新缓存? 1.初次读取计算属性时 2. 所依赖的数据发送变化时
监视相比较计算属性能开启异步任务
切换
⭐⭐⭐⭐
- 被Vue管理的函数,最好写成普通函数,这样this才是vm对象 或 组件实例对象
- 所有不被Vue所关闭的函数(定时器的回调函数,ajax的回调函数,Promis的回调函数),最好写成箭头函数(监听函数没有this,就会往外找),这样这样this才是vm对象 或 组件实例对象。
对要显示的数据进行特定格式化后再显示,(适用于一些简单逻辑的处理)(Vue3已经移除)
(其实用方法,计算属性都能完成)
当前时间戳:{{time}}
转换后时间:{{time | timeFormater()}}
转换后时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss')}}
生命周期函数里面的this都是vm 或者 组件实例对象
所有的函数看图片!
beforeCreate
:此时无法通过vm访问data中的数据和methods中的方法(即数据检测,数据代理创建之前)
created
⭐:此时就可以通过vm访问data中的数据和methods中的方法
beforeMount
:挂载之前,页面呈现未经Vue编译的DOM结构(在此时刻自己操作DOM不会生效,因为Vue在下一步会替换你的操作)
mounted
** ⭐:挂载完毕,页面呈现经过Vue编译的DOM结构。完成了模板的解析并把初始的真正的DOM放入(即把虚拟DOM转化为真实DOM后,只调用一次), 至此初始化过程结束。一般再此开启定时器,发送请求,绑定自定义事件,订阅消息…等初始化工作**
beforeUpdate
:此时数据是新的,但页面是旧的
updated
:此时数据是新的,页面也是新的
beforeDestroy
⭐:此时vm的data,motheds,指令都还可以用,马上执行销毁过程(但再次操作数据页面不在触发更新了),一般进行关闭定时器,取消订阅消息,解除自定义事件…等收尾工作(销毁可以调用vm.$destroy())
destroyed
:已经销毁
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 --registry=https://registry.npm.taobao.org
(下载前可以修改一下
npm
默认的下载路径,防止占用C盘空间。-g代表全局安装)安装
vue-cli
cnpm install @vue-cli -g
:vue-cli最新版,输入vue ui
即可进入图形化创建项目界面
vue list
可查看可以基于哪些模板创建vue应用程序
vue-cli3版本以上创建项目:
vue create 项目名
cd 项目名
进入项目,npm run serve
运行项目http://localhost:8080/
即可看到脚手架帮我们写好的HelloWord(ctrl+c停止)或者进入你要创建到的目录,执行vue ui
图形化界面创建项目:
文件目录
├── 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)
webpack
:一个现代JavaScript应用程序的静态模块打包器(module bundler)。当webpack处理应用程序时,他会递归的构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有的这些模块打包成一个或多个bundle。当下最热的前端资源模块化管理工具和打包工具,可以将许多松散耦合的模板按照依赖和规则打包成符合生产环境部署的前端资源。
⭐ES6规范,EcmaScirpt6标准增加了JavaScirpt语言层面的模块体系定义。尽量静态化,使编译时就能确定模板依赖关系,以及输入输出的。容易进行静态分析,但有些原生浏览器还没正常这个。可以使用webpack把ES6规范打包成ES5规范。
import "jquery" export dunction doStuff() {} module "localModele" {}
安装
webpack
:
cnpm install webpack -g
cnpm install webpack-cli -g
webpack -v
,webpack-cli -v
查看是否成功配置:创建
webpack.config.js
配置文件,有entry,output,module,plugins,resolve,watch等属性…(了解一下)
使用webpack
:
D:\webpack-study
modules
目录写js代码,要有这个主入口,main.jswebpack.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变化就重新打包(ctrl+c停止)
概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
什么时候使用vuex:
原理图:
安装:
Vue 2 匹配 Vuex 3 。Vue 3 匹配 Vuex 4 。
我用的vue2,安装vuex3版本:
npm install vuex@3 --save
基本使用:
初始化数据state,配置actions,mutations,操作文件store.js
组件中读取vuex中的数据$store.state.数据
组件中修改vuex中的数据$store.dispatch('action中的方法名',数据)
,或者$store.commit('mutations中的方法名',数据)
若没有网络请求或其他业务逻辑,组件中也可越过actions,即不写dispatch
直接调用commit
Count.vue相当于Controller,action相当于Service,mutatisons相当于Dao
src/store/index.js
该文件用于创建Vuex中最为核心的store,⭐⭐⭐
import Vue from 'vue'
import Vuex from 'vuex'Vue.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 './store'Vue.config.productionTip = falsenew Vue({store, // vm和所有的组件实例对象有个$store对象了render: h => h(App)
}).$mount('#app')
Count.vue
:单个组件,案例使用(多个组件操作$store.state都一样操作即可)
当前求和为:{{ $store.state.sum }}
当前求和方法十倍为:{{ $store.getters.bigSum }}
mapState
方法:用于帮助映射 state
中的数据为计算属性
例如:$store.state.sum -> sum
,就不用写这么长了
import {mapState} from "vuex"computed: {// 借助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 "vuex"computed: {//借助mapGetters生成计算属性:bigSum(对象写法一)...mapGetters({bigSum:'bigSum'}),//借助mapGetters生成计算属性:bigSum(数组写法二)...mapGetters(['bigSum'])
}
mapMutations
方法:用于帮助生成与 mutations
对话的方法,即$store.commit(xxx)
的函数
import {mapMutations} from "vuex"methods: {//靠mapActions生成:increment方法、decrement方法(对象形式)...mapMutations({increment:'JIA', decrement:'JIAN'}),//(数组形式),这样的话使用方法就得...mapMutations(['JIA','JIAN']),
}// 生成的是这样的。和我们自己写的还是有一点区别的,
// 自动生成的话就要传参了
methods: {increment(value) {this.$store.commit('JIA', value)}
}
mapActions
方法:用于帮助生成与 actions
对话的方法,即$store.dispatch(xxx)
的函数
import {mapActions} from "vuex"methods:{//靠mapActions生成:incrementOdd、incrementWait(对象形式)...mapActions({incrementOdd:'jiaOdd', incrementWait:'jiaWait'})//(数组形式)...mapActions(['jiaOdd','jiaWait'])
}// 生成的样式和上面的一样也要传数据
mapActions,mapMutations使用时,若需要传递参数,在模板中绑定事件时传递好参数,否则参数是事件对象。
目的:让代码更好维护,让多种数据分类更加明确
修改store/index.js
文件,为了解决不同模块命名冲突的问题,将不同模块的namespce: true
,之后在不同页面中引入getter, actions, mutations
时,需要加上所属的模块名。
// 求和相关的配置 (可以把这个countAbout写到一个文件中,然后暴露)
const countAbout = {namespaced: true, // 开启命名空间(默认false)state: {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'})
}
vue-router
:官方的路由管理器,它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌
专门用来构建SPA(single page web application)单页面应用,而且点击页面中的导航链接不会刷新页面,只会做页面的局部更新。
功能:
Vue 2 匹配 Vue-Router 3 。Vue 3 匹配 Vue-Router 4 。
安装路由插件:当前项目下安装
vue-router
,进入当前项目目录 (我用的vue2,先安装vue-router3版本)
- nmp:
cnpm install vue-router@3 --save-dev
- cdn:
单HTML路由演示:
Hello App!
Go to Foo Go to Bar
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.vue'Vue.use(VueRouter) // 应用路由插件const routes = [{path: '/',name: 'home', // name可以简化路由跳转,如果是二级路由就不用带一级路由的路径了,直接写name即可component: HomeView},{path: '/test',name: 'test',component: Test,children: [ // 嵌套路由,记得在Test组件中指定Abc组件的渲染位置,即使用{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.js'Vue.config.productionTip = falsenew Vue({router, // 安装了路由就有router这个配置项render: h => h(App)
}).$mount('#app')
实现切换使用
标签,active-class
属性可以设置高亮样式,vue帮我们自动切换高亮。
指定展示位使用
标签
当切换路由时,路由组件是被频繁销毁挂载的,可以使用keep-alive标签把要缓存组件包起来,让不展示的路由组件保持挂载,不被销毁
⭐⭐⭐⭐
,本质是个a标签,a标签的属性都可以写。
this.$router.push()
这种一般是按钮之类的使用这种跳转方式
this.$router.push({ path: "/lujing", // name: "lujing" 也行,前提得配置好路由名query: { value: 2 } // 传递参数,会用&拼接到url中,即 /lujing?value=2// 传递参数,会用/拼接到url中,即 /lujing/2 (router路由器中需要配置占位符,即 path: '/lujing/:value') // 注意:使用params传参不能用path,只能用name!name: "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构造方法的实例。 有push
,replace
,go
方法
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每个组件都不同,存放这自己的路由信息。
如果组件里面有定时器,并且我们写了在beforeDestory()
里面进行关闭定时器,销毁的时候会关闭定时器。
但如果我们使用keep-alive
缓存路由组件的话,就不会销毁组件,所以定时器也不会关闭,一直开着。所以有了下面这两个钩子:
路由组件所特有的两个生命周期钩子函数(类似:mounted -> activated, beforeDestory -> deactivated)
- 欢迎学习vue
- news001
- news002
对路由进行权限控制,类似拦截跳转
全局全局守卫:
src/router/index.js
:
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,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 // 导出
组件内守卫:
666
对于一个url什么是hash值? #
及其后面的内容就是hash值
hash值不会包含到http请求中,即hash值不会带给服务器
hash模式:
history模式:
切换:
const router = new VueRouter({mode:'history',routes:[...]
})export default router
移动端:Vant,Cube UI,Mint UI
PC端:Element UI,IView 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
按需引入⭐⭐:
安装:
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), })