文章目录
必备-10.@vue/cli
@vue/cli是什么
- @vue/cli(Command Line Interface):vue的命令行接口,我们称之为脚手架,其作用是帮助我们快速生成一个可以放到服务器上的项目
- 脚手架:把项目中需要的webpack配置项目都内部处理好,基于脚手架快速创建一个工程化
- 使用网址:https://cli.vuejs.org/zh/guide/installation.html
@vue/cli创建一个项目
第一步:安装@vue/cli
- 使用vue必须有nodejs
- 安装nodejs:(https://nodejs.org/en/) 验证
node -v(version)
使用npm(安装vue npm install vue) - 安装vue-cli:
npm install -g @vue/cli
验证 vue -V 使用vue
- 安装nodejs:(https://nodejs.org/en/) 验证
第二步:创建项目文件
-
1、创建一个文件夹(文件名不能包含大写字母),进入文件夹路径下的cmd窗口
-
2、使用命令创建vue项目:
vue create 项目名
-
3、选择版本信息:有vue2.0/vue3.0/自定义,三个选项,在项目真实开发中一般会用自定义,选择我们需要的插件
-
- Babel :兼容es6
- TypeScript : javascript的超集
-
-
4、选完之后要再次进行确认选择:
- node-sass是自动编译实时的,dart-sass需要保存后才会生效
-
5、选择vue版本,目前选择vue 2.x
-
6、选择哪个配置文件来配置babel等:
-
In dedicated config files
:在专用配置文件中In package.json
:在package中
-
-
7、是否保存你的自定义选项,以便下次创建时直接使用:
-
8、等待文件创建完成:
项目创建失败怎么办
-
第一步:先删除nodejs->
控制面板---》程序(卸载)-----》nodejs(右键单击,卸载)
-
第二步:重新安装:
- 重新安装 node:https://www.cnblogs.com/liuqiyun/p/8133904.html
-
第三步:重启电脑
-
第四步:执行命令
-
1. node -v 2. npm cache clean --force 3. npm install 4. npm install -g @vue/cli 5. vue --version
-
第三步:启动项目
- cd my-project
- npm run serve
- 开发环境启动项目:
npm run serve
- 生产环境启动项目:
npm run build
- 开发环境启动项目:
第四步:访问项目
-
- local:本地访问的路径
- **network:**网络访问的路径
第五步:vscode使用Vue
- 安装Vetur插件->重启vscode->格式化
xxx.vue
代码:shift+alt+f
vue项目的基本结构
-
文件夹整理:
- node_modules
- package.json
- babel.config.js
- vue.config.js
- public:
index.html、favicon.ico
- src:
main.js、App.vue、api、assets、lib、store、router、commponent、pages(views)
-
|-
node_modules
:项目的依赖库- |-…
-
|-
package.json
:依赖管理、脚本命令记录项目需要的依赖(开发&生产),部分webpack配置项、可执行脚本…scripts(脚本命令)、devDependencies(开发依赖)、dependencies(生产依赖)、browserslist(浏览器列表)
-
|-
babel.config.js
: webpack打包的时候,会读取这里的配置项,然后基于babel-loager把ES6代码编译为ES5 -
|-
src
:(source)所有需要webpack编译的内容都要放在这个目录- |-
main.js
:程序入口(webpack打包入口) - |-
App.vue
:页面入口 - |-
api
:(Applicaion Programming Interface)所有接口请求管理&axios的二次封装 - |-
assets
:静态资源项目需要的静态文件 - |-
lib
:(library)依赖工具库(部分公司)存放抽离的JS方法 - |-
store
:仓库存放vuex的管理 - |-
router
:路由存放路由的管理 - |-
commponent
:公有组件存放公有的组件 - |-
pages(views)
:页面组件存放页面组件 - |-…
- |-
-
|-
public
:存放页面模板- |-
index.html
:默认的页面入口 - |-
favicon.ico
:标题图标
- |-
-
|-
vue.config.js
:在项目根目录中,基于这些文件编写一些配置,母的是修改默认的webpack配置项
特殊:
- 一般来讲,public/index.html页面模板中不会编写啥内容,最后都是基于webpack把各组件(或各页面)的内容合并编译后,插入到index.html的#app的容器中
- 但是部分内容还是需要在这个页面模板中写一写的:
- 我们后期可以基于vue3中的传送门技术,把组件中的部分内容,插入到页面除#app外的其他部分容器中,此时我们需要在页面中写一些其它容器!!
- 我们也可以把一些纯静态的内容,而且是不想基于vue的模板编译的,写死在页面模板中!(这样做的很少,因为即使写在组件中,我们也可以基于
v-pre
指令让其跳过编译) - 因为webpack最后会把项目中的css或js合并压缩打包为一个文件[我们后期会做分割打包,例如:路由懒加载],并且插入到页面中,这样在页面渲染的时候,加载CSS或JS就会慢,如果我们想在没有加载完这些文件之前,先呈现给用户Loading(或骨架屏)效果,来减少白屏事件,那么我们就在页面模板中,单独写一写骨架屏的实现,这些代码,是不能和主要内容打包在一起的。
- webpack打包,是按照
ES6Moule
或CommonJS
模块规范,分析出模块间的依赖,按照依赖打包在一起,所以需要我们的模块支持ES6Module和CommonJS规范,如果某个模块不支持这些规范:- 方式一:手动改为支持的:
module.exports=xxx
- 方式二:在页面模板中,基于
script src
导入,后期基于window.xxx
使用
- 方式一:手动改为支持的:
- …
各配置文件代码解析
package.json
- 默认的生成的package.json:不仅可以编译 es6语法,也可以编译vue语法
babel.config.js
public和src
重写webpack配置
-
@vue/cli 为了美化项目,把写好的webpack配置项都放在 node_modules中了
- 想要修改其配置项,就需要自己在package.json同级目录下创建 vue.config.js 文件,在文件中修改它的一些配置【vue脚手架设置好的规则】
-
配置地址:https://cli.vuejs.org/zh/config/#vue-config-js
-
/* 修改脚手架默认设置好的webpack配置项 */ module.exports = { // 打包后,在index.html导入的资源,前面是 “./”「默认是 “/”」 // 例如: <script src="js/chunk-vendors.ffeebf7c.js"></script> // 好处:后期在服务器端进行部署的时候,不论部署到根目录还是其它目录,都可以正常访问资源 publicPath: './', // ESLint词法检测 true/warning & false & default/error // 下面写法:成产环境下不开启词法检测,开发环境下开启 lintOnSave: process.env.NODE_ENV !== 'production', // 生产环境中,不编译SourceMap文件,提高打包编译的速速「SourceMap是有助于压缩后的文件调试」 productionSourceMap: false, /* // configureWebpack:发现默认的webpack配置项不够实现我们的需求,需要自己再次新增一些配置规则 configureWebpack: { plugins: [] }, // chainWebpack:发现默认的webpack配置项的规则需要修改 chainWebpack: config => { // config:默认设置好的配置项 config.module .rule('vue') .use('vue-loader') .tap(options => { return options; }); }, */ /* // 设置跨域代理 devServer: { // proxy: 'https://www.jianshu.com', proxy: { '/jianshu': { target: 'https://www.jianshu.com', changeOrigin: true }, '/zhihu': { target: 'https://www.zhihu.com', changeOrigin: true } } }, */ };
如何修改脚手架配置
-
publicPath:
【公共路径】打包后,指定导入文件资源的起始路径- 默认值"/":根目录,表示所有引入的文件从项目根目录中找,这样我们必须保证打包后的文件部署到服务器的根目录下,否则会出现找不到资源;
- 一般修改为"./":相对路径,这样无论部署到哪,都是在自己所在的位置开始找
-
outputDir:
【输出路径】打包成功后文件输出的路径- 默认值"":会默认放到dist目录项
-
assets
:【静态资源】指定生成的静态页面(css/js/img/fonts)放到哪个文件夹下- 默认值"":css文件放到css文件夹下,js文件放到js文件夹下
-
pages
:【多页面】配置多页面[不同的页面,分别指定入口,出口,依赖的模块…,最终打包出多个页面] -
lintOnSave
:【在保存时检测】设置ESLint语法检测的规则[“true”、“false”、“warning”、“default”、“error”]-
ESlint:检测代码编写规范的,不同公司有不同规则,代码不符合规则是不允许编译的
- 到工作中,根据项目中设定的ESLint规则,需要在vs中基于eslint插件,配置出和项目相同的规则
-
默认值"default":【同error】开发或生产环境都需要检测,而且只要有一个不符合语法规范,则编译失败
-
设置为"true":【同warning】有语法规范问题,只是警告,但是编译是让其成功的
-
设置为"false":取消ESlint词法规范检测
-
工作中:开发环境下设置为true,生产环境下设为false(加快打包速度)
-
//获取scripts脚本命令中的ENV变量 const ENV=process.env.NODE_ENV; //根据ENV判断 lintOnSave: ENV!=="production";
-
-
-
transpileDependencies
:[]【依赖关系】默认情况下,所有的node_modules中的模块,都不会基于babel-loader进行编译(也就是不会把这里的ES6转为ES5),所以为了考虑浏览器兼容,我们需要把node_modules中基于ES6代码写的模块,也进行编译!!(只不过我们使用的模块,一般都是已经编译为ES5代码的了!!) -
productionSourceMap
:【生产源映射】true 在生产环境打包的时候,是否生成资源文件对应的map文件[作用:方便在线调试]- 真实开发时:设为false,以此让打包速度更快,而且我们不允许在线调试的
-
crossOrign
:【跨域访问修改请求源】当link、script标签请求服务器端资源时,将请求源改为想要的网址:http:www.baidu.com
-
---------------------------------高级玩家玩的------------------------------
-
configureWebpack
:【配置webpack】脚手架中没有设置的,我们基于configureWebpack加入进去 -
chainWebpack
:【链式修改webpack】脚手架设计好的,我们自己去修改[链式写法修改] -
---------------------------------------end-------------------------------------
-
devServer
【开发服务器】:修改webpack-dev-server的配置项 -
devServer.proxy
:【开发服务器的代理】实现proxy跨域代理-
devServer:{ proxy:{ //请求地址是以/api开始的 '/api':{ //代理到的真实服务器 target:'http://www.jianshu.com', //把发送请求时的origin改为代理的服务器源 changeOrigin:true, pathRewrite:{ //请求地址:'/api/user/list' //代理服务器地址:'http://127.0.0.1:9999/api/user/list' //真实请求服务器:'http://127.0.0.1:9999/user/list' //把地址中的'/api'替换为"" '^/api':'' } }, //让所有的请求都代理到这个服务器,向这个服务器发请求 '':{ target:'http://www.jianshu.com', changeOrigin:true } } }
-
请求地址是以/api开始的:回去找proxy中的’/api’代理
-
语法按照:
http-proxy-middleware
-
真实项目中:如果请求的资源都在一个服务器上,只要设置一个’'代理即可,如果不在同一个服务器,要设置多个代理
-
vue 使用 less
- vue中已经配置好了less的转换配置,如果想用,直接安装less需要的包就可以
- 安装less加载器:
npm i less@3 less-loader@7 --save-dev
- **注意:**使用低版本,否则报错,脚手架不兼容高版本
vue项目的兼容性
- 检查版本兼容网址:https://cli.vuejs.org/zh/guide/browser-compatibility.html#browserslist
- 注意:vue的核心是基于Object.defineProerty 实现数据劫持的,所以及不论怎么处理,IE8及以下都不兼容
- 方案一:调整 package.json 中的 browserslist 配置项中
- css3的样式会基于这个列表自动设置不同的前缀
- es6等代码也会基于这个列表,自己进行语法编译
- 方案二:基于@babel/polyfill 进行处理
- 方案一:调整 package.json 中的 browserslist 配置项中
兼容CSS
- **功能:**webpack不能识别less格式文件,当我们遇到这样格式的文件时,需要通过loader进行一系列处理,让它变得能让webpack编译
$ npm i css-loader style-loader less less-loader autoprefixer postcss-loader –save-dev
- 各个loader加载器的功能:
$ less& less-loader
:实现把less编译为css$ postcss-loader & autoprefixer
:给一些不兼容的css3样式属性,自动设置前缀css-loader
:编译css代码中的@import和url这样的代码style-loader
:把编译好的css插入到页面的Head的style中,搞成内嵌式
module.exports = {
//=>配置模块加载器LOADER
module: {
//=>模块规则:使用加载器(默认从右向左执行,从下向上)
rules: [{
test: /\.(css|less)$/, //=>基于正则匹配哪些模块需要处理
use: [
"style-loader", //=>把CSS插入到HEAD中
"css-loader", //=>编译解析@import/URL()这种语法
"postcss-loader", //=>设置前缀
{
loader: "less-loader",
options: {
//=>加载器额外的配置
}
}
]
}]
}
}
postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')//作用:自动添加-webkit-等前缀
]
};
package.json
// https://github.com/browserslist/browserslist
"browserslist": [//筛选浏览器的版本范围
"> 1%",
"last 2 versions"
]
main.js
import "./assets/index.less";
**mini-css-extract-plugin **
抽离CSS内容
- 功能:默认的css样式会插入到html文件的
style
标签中,这个插件会将css样式抽离出来形成新的css文件,并以link的方式导入到对应的html文件中
==插件网址:==https://www.npmjs.com/package/mini-css-extract-plugin
下载插件:$ npm i mini-css-extract-plugin –save-dev
const MiniCssExtractPlugin=require('mini-css-extract-plugin');
module.exports = {
plugins: [
//=>使用插件
new MiniCssExtractPlugin({
//=>设置编译后的文件名字
filename: 'main.[hash].css'
})
],
module: {
rules: [{
test: /\.(css|less)$/,
use: [
// "style-loader",
//=>使用插件中的LOADER代替STYLE方式
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"less-loader"
]
}]
}
}
- 重点:导入插件后,用
MiniCssExtractPlugin.loader
代替"style-loader"
兼容ES6
-
什么是babel:Babel 是一个工具链,主要用于在当前和旧浏览器或环境中将 ECMAScript 2015+ 代码转换为向后兼容的 JavaScript 版本。
-
**babel网址:**https://babeljs.io/
-
需要加载的插件或加载器:
-
$ npm i babel-loader @babel/core @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime –save-dev $ npm i @babel/runtime @babel/polyfill
-
-
各插件的作用:
- 处理普通的JS语法:
$npm i babel-loader @babel/core @babel/preset-env --save-dev
- 处理class的语法:
$npm i @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime --save-dev
- 处理 promise 等特殊语法:
$ npm i @babel/plugin-proposal-decorators –save-dev
$ npm i @babel/runtime @babel/polyfill
- 处理普通的JS语法:
module.exports = {
module: {
rules: [{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
//=>转换的语法预设(ES6->ES5)
presets: [
"@babel/preset-env"
],
//=>基于插件处理ES6/ES7中CLASS的特殊语法
plugins: [
["@babel/plugin-proposal-decorators", {
"legacy": true
}],
["@babel/plugin-proposal-class-properties", {
"loose": true
}],
"@babel/plugin-transform-runtime"
]
}
}],
//=>设置编译时忽略的文件和指定编译目录
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}]
}
}
兼容Promise
- 基于webpack 配置规则,这个class 编译成为ES5语法,但是Promise无法编译
解决:需要在 index.js 引入
- 基于@babel/polyfill处理ES6内置方法的兼容「例如:promise,polyfill中自己实现了一套兼容的promise」
import '@babel/polyfill';
模块化
模块化开发的目的?
- 模块化主要针对于js逻辑性文件,将JS文件的主要功能暴露出去,供其他模块复用,这就是模块化
组件化
什么是组件化开发?
-
组件化:
- 功能性组件:【UI组件库中提供的一般都是功能性组件:element/iview/antdv/vant/cube…】
- 一般UI组件库提供的功能组件就够用了
- 偶尔UI组件库当中不存在的,才需要自己封装【难点】
- 我们经常会把功能性组件进行二次封装,(结合自己的业务逻辑)【特色亮点】
- 业务性组件:
- 通用业务性组件:好多页面都需要用到的,我们把其封装为公共的组件
- 普通组件:
- 功能性组件:【UI组件库中提供的一般都是功能性组件:element/iview/antdv/vant/cube…】
-
以后开发项目,拿到设计稿的第一件事情,就是划分组件:
- 原则:按照功能板块划分、本着复用性原则、拆的越细越好(这样才能更好的实现复用)
vue的pc端组件库?
element-ui
:饿了么- https://element.eleme.cn/#/zh-CN/
- vue2.xx:elemnetui
- vue3.xx:element plus
antdv
:蚂蚁金服iview
:京东
如何在项目中使用功能性组件?
- 第一步:安装
element-ui
:$npm i element-ui -s
- 第二步:导入:
- 完整导入:整个组件库都导入进来,想用什么直接用Vue.use(xxx)即可
- 缺点:如果我们只用几个组件,则无用的导入组件会造成项目打包体积变大[不好],所以项目中推荐使用按需导入
- 按需导入:
- 需要安装依赖
$ npm install babel-plugin-component
- 需要安装依赖
- 完整导入:整个组件库都导入进来,想用什么直接用Vue.use(xxx)即可
局部组件
vue中如何创建局部(私有)组件?
-
创建一个
xxx.vue
文件,就是创建了一个组件,组件包含:结构、样式、功能-
结构:基于template标签构建:
- 只能有一个根元素节点(vue2中)
- vue的视图是基于template语法构建的(各种指令&小胡子…),最后vue会把其编译为真实DOM插入到页面指定的容器中:
- 首先基于
vue-template-compiler
插件把template语法编译为虚拟DOM[vnode],其次把本次编译出来的vnode和上次的进行比较对比,计算出差异化的部分[DOM-DIFF]最后把差异化的部分变为真实DOM放在页面中渲染
- 首先基于
-
样式:基于style标签构建:可以添加一些标签属性
lang="less"
:指定使用的css预编译语言[需要提前安装对应的loader]scoped
:指定当前编写的样式是私有的,支队当前组件中的结构生效,后期组件合并在一起,保证样式之间不冲突【保证样式私有化】
-
功能:通过script标签来处理
-
export default{ name:'test', //vue中的data data(){ return { } } }
-
导出的这个对象是VueCommponent类的实例(也是Vue的实例):对象-》VueCommponent->prototype->Vue.prototype
-
在对象中基于各种options api[例如:data、methods、component、watch、filters、生命周期函数…]实现当前组件的功能
- 在组件中data不再是一个对象,而是一个"闭包"
-
-
如何使用一个私有组件?
-
需要使用私有组件的时候,需要先导入
import Test from "./Test.vue";
-
然后注册:这样就可以调用组件进行渲染了
-
<template> <div id="app"> //3.使用组件:可以使用单闭合或双闭合 <Test></Test> <Test> </div> </template> <script> //1、导入组件 import Test from "./Test.vue"; export default { name: "App", components:{ //2、注册使用的组件 Test, } }; </script>
-
全局组件
vue中如何创建全局组件?
-
@表示src根目录
-
第一步:创建一个局部组件,每一个vue文件都是一个局部组件
-
export default{ name:'test', //vue中的data data(){ return { } } }
-
-
第二步:在main.js入口中,导入局部组建Vote,把其他注册为全局组件
-
// 创建一个全局组件 import Vote from '@/Vote.vue'; //调用方法绑定全局组件 Vue.component("Vote",Vote)
-
-
第三步:在vue的template中直接调用组件,不用再在components中注册
-
//3.使用组件:可以使用单闭合或双闭合 //可以在kebab-case与CamelCase之间转换 <Test></Test> <Test>
-
调用组件时的注意事项?
- 调用组件的时候,可以使用:
- 双闭合:
<Test></Test>
- 双闭合的方式可以使用插槽(slot)
- 插槽的作用:让组件具备更高的复用性(或扩展性)
- 我们封装好一个组件,把核心部分都实现了,但是我们期望用户调用组件的时候,可以自定义一些内容,防止在已经封装好的组件内部:
- 第一步:组件内部留好位置
<slot></slot>
- 第二步:把双闭合标签中的内容插入到
<slot></slot>
中
- 第一步:组件内部留好位置
- 单闭合:
</Test>
- 组件的调用可以用
kebab-case
或CamelCase
,两个之间可以相互转换:- 官方推荐调用时用kebab-case,其他时候用CamelCase
- 双闭合:
插槽
**slot插槽:**程序员开发的组件为了保证复用性和可扩展性,会在自己的组件上用<slot></slot>
标签添加很多插槽,其他人用这个组件,可以向对应插槽插入自己想实现的代码,实现组件的扩展和复用
-
插槽分为了默认插槽、具名插槽、作用域插槽,我们以Test组件为例
-
默认插槽:只需要在调用组件
<Test><Test>
内插入我们想要的插入的html代码,会默认放到组件源代码的<slot name="default"></slot>
插槽中 -
具名插槽:组件中预设好多插槽位置,为了后期可以区分插入到哪,我们把插槽设置名字
-
在调用组件
<Test><Test>
内自己写的代码,我们用template包裹代码,并把v-slot:xxx写在template上,这时就会将xxx里面的代码,包裹到组件源代码的<slot name=”xxx“></slot>
的标签中 -
组件内部:
<slot name="xxx">
默认名字是default -
==调用组件:==需要把v-slot写在template上
-
<template v-slot:xxx> ... </template> <template> ... </template>
-
v-slot可以简写为#:#xxx
-
-
-
==作用域插槽:==把组件内部定义的数据,拿到调用组件时候的视图中使用
-
组件中data内的数据只能在本模块中使用,如果想让调用组件的插槽也能获取数据,就需要对组件内对的slot做bind绑定数据,调用组件的template标签做
#top="AAA"
,获取数据 -
组件内部:
<slot name="top" :list="list" :msg="msg"></slot>
- 把组件中的list赋值给list属性,把msg赋值给msg属性,插槽中提供了两个作用域属性:list/msg
-
调用组件:
<template #top="AAA"></template>
-
定义一个叫做AAA的变量,来接收插槽中绑定的所有数据(对象格式)
-
如果插槽名是default则使用
v-slot="AAA"
或:default="AAA"
获取数据//组件传过来的是一个对象,我们获取的AAA数据是下面的 AAA={ list:[...], msg:... }
-
-
-
父子组件之间数据传参
1.调用组件的时候,如何操作?
-
调用组件的时候,我们可以基于"属性 props"把信息传递给组件
- 原因:如果组件中展示的信息不固定,需要调用的时候告诉组件,此时我们就可以基于属性处理了
- 如果只是想传递一些数据给组件,我们基于属性处理
- 如果想把一些自定义的结构和内容插入到组件指定的信息,那么我们就需要使用插槽
- 两者最终目的:都是支持用户自己定义组件呈现的内容实现复用和扩展
- 原因:如果组件中展示的信息不固定,需要调用的时候告诉组件,此时我们就可以基于属性处理了
-
调用组件:
<Vote title="xxx" :supNum="10" :oppNum="2"></Vote>
- 我们传给组件的值,默认是字符串类型的,比如title
- 如果想传数字类型的,则需要调用v-bind或冒号的形式传值
- 我们每调用一次Vote,都会生成一个独立的
VueComponent
的实例
-
组件内部:基于props注册使用进来的属性(假如:传递的属性有多个,需要使用哪些,就注册哪些即可,不注册的不能在当前组件视图中使用)
-
export default{ //1、基于props注册的属性,会直接挂载到当前组件的实例上(可以直接在视图上基于title进行渲染)->this.title或者this.$props.title //2、属性title做了get/set劫持 //保证传递进来的属性值发生改变,当前组件可以重新渲染 //3、传递进来的属性是"只读"的;我们可以拿来使用,但是不允许在组件内部去修改,想要修改只能重新调用组件传递新的信息进来=>this.title=xxx(错误的) props:["title",...] }
-
-
props可以是对象的格式,这样在注册属性的同时,也可以做属性的规则校验
-
props:{ //title:String,设定传递属性类型 //title:[String,Number],可以是多个类型 title:{ type:String, required:true//设置为必传:如果没传这个属性,控制台抛出警告,视图正常渲染 }, supNum:{ type:Number,//传递的类型和要求不一致,控制台也会有警告 default:0//(不是必传)如果不传递值,使用默认值 } }
-
-
每创建一个组件其实相当于创建一个自定义类,而调用这个组件就是创建VueCommponent(或者Vue)类的实例
- 实例(this)->VueComponent.prototype->Vue.prototype->Object.prototype
- 当前实例可以访问Vue.prototype上的一些公共属性和方法
虚拟DOM
什么是虚拟DOM对象?
-
虚拟DOM对象:
_vnode
,作用:-
原理:vue内部自己定义的一套对象,基于自己规定的键值对,来描述视图中每一个节点的特征:
- tag标签名
- text文本节点,存储文本内容
- children:子节点
- data:属性
-
第一步:基于
vue-template-compiler
去渲染解析 template 视图,最后构建出上述的虚拟DOM对象 -
第二步:组件重新渲染,又重新生成一个 _vnode
-
第三步:对比两次的 _vnode. 获取差异的部分
-
第四步:把差异的部分渲染为真实的DOM
-
真实DOM let elem=document.createElement(_vnode.tag); .... #app.appendChlild(elem);
-
-
实际开发场景?
- 传递给组件的属性是==“只读的==”,如果直接把属性渲染到视图中,渲染的内容就固定了,但是组件内部后续的某些操作,想修改呈现的内容,我们肯定不能修改属性值,那么该如何处理?
- 第一步:把传递的属性接收后,赋值给组件的状态
- 第二步:视图渲染的是状态,后期改变的也是状态即可
状态值&属性值
组件中的script中存在的状态值和属性值?
- 状态值:data中的数据值称为状态值
- 属性值:props中的数据值称为属性值
- 状态值和属性值是直接挂载到
_vode
对象的私有属性中(所以状态值和属性值名字不能重复) - 我们在视图
template标签
中调用状态值和属性值,不需要加this,直接调用状态名或属性名 - 我们在功能
script标签
中调用状态值和属性值,需要加this调用 - computed(计算属性):也是挂载实例上的,所以他们三个都不能重名
组件库
vue的pc端组件库?
element-ui
:饿了么- https://element.eleme.cn/#/zh-CN/
- vue2.xx:elemnetui
- vue3.xx:element plus
antdv
:蚂蚁金服iview
:京东
如何在项目中使用功能性组件?
- 第一步:安装
element-ui
:$npm i element-ui -s
- 第二步:导入:
- 完整导入:整个组件库都导入进来,想用什么直接用Vue.use(xxx)即可
- 缺点:如果我们只用几个组件,则无用的导入组件会造成项目打包体积变大[不好],所以项目中推荐使用按需导入
- 按需导入:
- 1、需要安装依赖
$ npm install babel-plugin-component
- 1、需要安装依赖
- 完整导入:整个组件库都导入进来,想用什么直接用Vue.use(xxx)即可
样式私有化
-
在Vue中我们基于scoped设置样式私有化之后:
-
会给组件创建一个唯一的ID(例如:
data-v-5f109989
) -
在组件视图中,我们编写所有元素(包含元素调用的UI组件),都设置了这个ID属性;但是我们调用的组件内部的元素,并没有设置这个属性!!
-
总结:只要是自己写的(含插槽内容)、以及直接调用的组件都设置这个属性(Attribute):但组件内部元素是不设置的
-
<div data-v-5f1969a9 class="task-box"> <button data-v-5f1969a9 type="button" class="el-button el-button--primary"> <span>新增任务</span> </button> </div>
-
而我们编写的样式,最后会自动加上属性选择器:
-
.task-box { box-sizing: border-box; ... }
-
-
编译后成为:
-
.task-box[data-v-5f1969a9]{ box-sizing: border-box; }
-
-
-
组件样式私有化的原理:设置唯一的属性(组件ID)、组件内部给所有样式后面都加上该属性选择器
-
问题:组件内部的元素没有设置这个属性,但是我们编写的样式是基于这个属性选择器在css设置的选择器,
-
解决:在组件内部的元素选择器前加
/deep/
:-
*,/deep/.el-textarea__inner, /deep/.el-input__inner{ border-radius: 0; }
-
-
API
-
在真实项目中,我们会把数据请求和axios的二次封装,都会放到src/api路径下进行管理
-
小技巧:
-
//main.js import api from '@/api/index'; // 把存储接口请求的api对象挂载搭配Vue的原型上:后续在各个组件基于this.$api.xxx()就可以发送请求了,无需在每个 组件中再单独导入这个api对象。 Vue.prototype.$api=api;
-
组件传参
组件传参的分类7种:
- 父组件向子组件传参:props
- 子组件向父组件传参:发布订阅(@xxx给子组件标签自定义事件、$emit)
- 组件相互传参(兄弟):发布订阅( o n 、 on、 on、emit)【2和3传参是一种】
- 祖先向后代传参==(provide[提供],inject[接收])==
- vue实例属性传参==( p a r e n t 、 parent、 parent、children[n]、 r o o t 、 root、 root、refs)==
- vuex
- localStorage sessionStorage
父组件向子组件传参
-
父组件向子组件传参:props
-
首先你要有父组件跟子组件
-
第一步:父组件在组件调用标签中自定义属性
-
<Coma msg="hello" :numa="num"></Coma>
-
-
第二步:子组件通过props接收(数组,对象)
-
// props的值是只读的 props:["msg","numa"]
-
props中的属性是只读的,子组件不能修改这些值,否则会报错
-
props可以是对象或数组类型,对象可以对数据做校验,数组不能
-
-
子组件向父组件传参
-
子组件向父组件传参,基于发布订阅(@xxx给子组件标签自定义事件、$emit)
-
第一步:父组件在调用子组件的标签上需要自定义一个事件,这个事件及绑定的方法就会添加到子组件的事件池中:底层实质上是调用了this.$on(“myEvent”,fn)
-
<Coma @myEvent="getData"></Coma>
-
-
第二步:在子组件中执行父组件给自己定义的事件,用
this.$emit("myEvent",parm1,parm2,...)
方法-
methods:{ transferData(){ //第一个参数是要执行的事件 //第二个参数及以后的参数是传的数据值 this.$emit("myEvent",this.msg,this.flag) } }
-
-
第三步:定义getData的方法
-
methods:{ //n就是子组件传的msg //flag就是子组件传的flag getData(n,flag){ this.n=n; this.flag=flag } }
-
-
组件相互传参(Eventbus)
发布订阅( o n 、 on、 on、emit)
-
b—>c传数据
- c向事件池中添加方法(自定义方法):$on
- b执行方法把参数传过去:$emit
-
第一步:全局的main.js中
-
// 创建一个全局的EventBus let EventBus=new Vue(); //将EventBus放在Vue的原型上,通过$bus来调用 Vue.prototype.$bus=EventBus;
- 作用:将EventBus看作定义在公有属性上的事件池(事件公交),之后基于这个
$bus.$on()
绑定的事件函数,在哪个vue实例上都可以基于$bus.$empty()
执行,还可以传值
- 作用:将EventBus看作定义在公有属性上的事件池(事件公交),之后基于这个
-
-
第二步:comc向事件池中绑定事件:
this.$bus.$on("事件名",函数)
-
created(){ this.$bus.$on("myEvent",(m)=>{ this.msg=m; }) }
-
-
第三步:comb从事件池中获取事件函数并执行:
this.$bus.$emit("事件名",想传的参数)
-
methods:{ transferData(){ this.$bus.$emit("myEvent",this.msg) } }
-
祖先和后代相互传参
(provide[提供],inject[接收])
- 第一步:祖先要使用provide方法传参,不是写在methods里面,与methods同级
- 第二步:后代使用inject属性接受祖先中的参数,inject是data中的数据,是数组类型
- 注意点:因为inject是数组类型,所以它符合如果数据项不是对象类型,则不做劫持,如果数据项是对象,则这个对象中的属性会做劫持。
vue实例属性传参
( p a r e n t 、 parent、 parent、children[n]、 r o o t 、 root、 root、refs)
- vue的实例中存在一些属性能够获取不同关系的元素,每调用一次组件(
<A></A>
)都会产生一个私有的vue实例,获取之后就可以基于这个元素获取其中的数据或方法了:this.$parent
:相对于子vue实例来说,获取父元素的整个vm实例,每个vue实例都只存在一个父实例- 子组件可以在父组件的任何生命周期函数中获取【父子组件的生命周期】
this.$children[n]
:获取第n个子元素的vm实例- 父组件只能在子组件
created
生命周期函数里或之后获取子元素【父子组件的生命周期】
- 父组件只能在子组件
this.$root
:获取根元素的vm实例(main.js中new 的Vue实例)this.$refs
:this的子元素中需要定义ref
属性:比如ref="xxx"
:- 如果ref定义在DOM标签中:
this.$refs.xxx
获取的是DOM对象 - 如果ref定义在子组件标签中:
this.$refs.xxx
获取的是子组件的vm实例
- 如果ref定义在DOM标签中:
父组件绑定在子组件标签中的事件,是无法触发的,如何解决?
@xxx.native
: 监听组件根元素的原生事件。
-
例子:
<my-component @click.native="onClick"></my-component>
-
原理:在父组件中给子组件绑定一个==原生(click/mouseover…)==的事件,就将子组件变成了普通的HTML标签,不加’. native’父组件绑定给子组件标签的事件是无法触发的
父子组件的生命周期
一、父子组件生命周期执行过程:
- 父->
beforeCreated
- 父->
created
- 父->
beforeMount
- 子->
beforeCreate
- 子->
created
- 子->
beforeMount
- 子->
mounted
- 子->
- 父->
mounted
二、子组件更新过程:
- 父->
berforeUpdate
- 子->
berforeUpdate
- 子->
updated
- 子->
- 父->
updated
三、父组件更新过程:
- 父->
berforeUpdate
- 父->
updated
四、父组件销毁过程:
- 父->
beforeDestory
- 子->
beforeCreate
- 子->
created
- 子->
- 父->
destoryed
五、父组件销毁子组件时执行的过程:
- 父->
beforeUpdate
- 子->
beforeDestory
- 子->
destoryed
- 子->
- 父->
updated
- 重点:父组件更新默认不会触发子组件更新,但是**如果子组件中绑定调用了父组件的数据aaa,父组件的aaa数据更新触发重新渲染时,使用aaa数据{{$parent.aaa}}的子组件也会触发更新**
vuex
-
vuex:状态管理库**(公共大仓库)**,集中式存储管理所有组件的状态值,相当于把所有Vue组件的状态数据放到一个公共数据库中,任何一个组件修改了公共数据库中的状态值,其他使用了该状态值的组件都会跟着刷新渲染这个值
-
Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源“而存在。这也意味着,每个应用将仅仅包含一个 store 实例
-
vuex的作用:
- 1、vuex是专为Vue.js应用程序开发的状态管理模式(集中式存储)—>公共仓库
- 2、缓存 keep-alive
localStorage
:本地存储,刷新有数据、数据永久sessionStorage
:会话存储,刷新有数据、关闭页面没有数据vuex
:不刷新,不关闭页面,就会保存以前的数据,刷新就不存在数据
-
vuex:“单向数据流”理念:
-
vuex的异步函数执行的过程:
vuex的五个核心属性
-
state
:相当于vue中的data -
getters
:相当于vue中的computed -
mutations
:相当于vue中的methods(同步) -
actions
:相当于vue中的methods(异步) -
Modules
:模块 -
在讲解vuex的五个核心属性之前需要先创建一个vuex仓库的实例:
-
//新建index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)//在vue上挂载vuex包,扩展 const store = new Vuex.Store({//创建Vuex的store实例 state: { count: 0 }, mutations: { increment (state) { state.count++ } } }) export default store; //在main.js中挂载,注意,这个store实例是挂载到了Vue的prototype上 new Vue({ el: '#app', store: store, })
-
state
-
state
:相当于vue中的data -
作用:存放所有组件能够共用的状态值
-
用法:
-
vuex实例仓库端定义:
-
const store = new Vuex.Store({ //在大仓库中存放一个count为0 state: { count: 0 } })
-
-
所有vue组件端调用:
-
//方式一:直接沿着原型链调用(不推荐没缓存) {{this.$store.state.count}} //方式二:放到computed中调用(有缓存) computed: { count () { return this.$store.state.count } } //方式三:使用辅助方法,放到computed中调用多个(推荐,有缓存) import { mapState } from 'vuex'//导入辅助函数Vuex.mapState,它返回的是一个对象 //第一种:计算属性中只存在映射过来的,参数是数组或对象,以数组为例: computed: mapState(['count'])// 映射 this.count 为 store.state.count //第二种:计算属性中存在映射过来的也存在自定义的,参数是数组或对象,以对象为例: computed: { addCount(){}, // 使用对象展开运算符将此对象混入到外部对象中 ...mapState({ //... }) }
-
-
getters
-
getters
:相当于vue中的computed -
作用:在vue组件获取state状态值之前,对状态值做格式化,再传给vue组件
-
参数:
state
:【默认参数】指向的是vuex的实例store里的stategetters
:【默认参数】指向的是vuex的实例store里的getters,可以根据它,获得getters中其他属性的信息
-
用法:
-
vuex实例仓库端定义:
-
getters: { getCountAdd: (state,getter )=> { return state.count+1+getter.getc;//0+1+666 } getc(){return 666} }
-
-
所有vue组件端调用:在computed中调用
-
import { mapGetters } from 'vuex';//导入辅助函数 //方式一:以数组作为参数执行辅助函数 computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'getCountAdd', 'getc', // ... ]) } //方式一:以数组作为参数执行辅助函数,可以自定义状态名 computed: { ...mapGetters({ // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount` doneCount: 'doneTodosCount' }) }
-
-
mutations
-
mutations
:相当于vue中的methods(同步) -
要点:mutations中的函数必须是同步的,不能放异步方法
-
作用:vue组件不能直接修改store大仓库中的状态值,(会导致页面与仓库不同步),如果想做到所有组件数据,与store内state状态值同步,就要经过mutations中的方法来修改
-
参数:
state
:【默认参数】指向当前vuex实例store的state对象payload
:载荷,【第二个参数】用来接收组件传给函数的参数,如果想传多个数据,载荷应该是一个对象- 第三个及以后的参数不会发送给mutations里的方法
-
用法:
-
vuex实例仓库端定义:
-
mutations: { //自增函数 increment (state, payload) { state.count += payload.amount } }
-
-
所有vue组件端调用:在methods中调用,
-
//方式一:使用store.commit方法可直接调用 methods:{ addCount(){ this.$store.commit('increment', { amount: 10 }) } } //方式二:使用辅助函数,参数为对象或数组 import {mapMutations} form "vuex";//导入vuex的辅助函数 methods:{ ...mapMutations(["increment"]),//数组传参 ...mapMutations({//对象传参 inc:"increment" }) } //调用 <telement> <div> <button @click="inc(1,2,3)">点击 </button> </div> </telement>
-
-
actions
-
actions
:相当于vue中的methods(异步) -
作用:mutation只能存储同步函数,actions就是将同步函数封装为异步函数
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
-
参数:
context
:【默认参数】指向vuex的实例store大仓库
-
用法:
-
vuex实例仓库端定义:
-
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { //定义自增方法 increment (context) { //异步函数 setTimeOut(function(){ //内部再调用了commit方法 context.commit('increment') },1000) } } })
-
-
所有vue组件端调用:在methods中调用
-
//方式一:使用store的dispatch方法调用触发 methods:{ addCount(){ this.$store.dispatch('increment') } } //方式二:使用辅助函数,参数为对象或数组 import {mapActions} form "vuex";//导入vuex的辅助函数 methods:{ ...mapActions(["increment"]),//数组传参 ...mapmapActions({//对象传参 inc:"increment" }) } //调用 <telement> <div> <button @click="inc(1,2,3)">点击 </button> </div> </telement>
-
-
modules
-
作用:减少单一状态树的shore对象存放数据导致的臃肿,将整个sotre对象拆分为多个模块module,每个模块都存在自己局部的
state、getters、mutations、actions、namespaced
,甚至仍然将这个模块继续向下拆分 -
namespaced:默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
-
如果希望你的模块具有更高的封装度和复用性,你可以通过添加
namespaced: true
的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。 -
我们在
...mapGetters("moduleA",["msg"])
,寻找的是moduleA
模块中的msg状态值,如果没有写moduleA
的话,它会直接去全局的store中找状态值msg
-
-
用法:
-
第一步:需要创建一个独立的模块:
-
//store/moduleA.js //就是vuex实例类型的对象 const mouduleA={ //存在state,mutations,actions,getters,namespaced。。。 state:{ msg:"我是moduleA", arr:[1,2,3,4,5,6] }, getters:{ getNum(state){ return state.arr.filter(item=> item%2==0) } } } //导出模块 export default moduleA;
-
-
第二步:在store实例中导入并挂载:
-
modules: { a:moduleA } }) //重点: //store挂载moduleA之后: //moduleA中的state对象会挂载到store的state对象上 store:{ state:{ a:{//重点:a指向的就是moduleA模块中的state对象 msg:"我是moduleA"; } } //moduleA中的mutations、getters、actions对象会挂载到store的对应对象上 //以getters为例 store:{ getters:{ "a/getNum":[2,3,4];//将子模块中计算属性的计算结果放入getters中 } //mutations、actions相同做法 } }
-
-
第三步:在vue组件中调用vuex的modules中:
-
//方式一:通过$store导入 this.$store.state.a.msg;//获取a模块中的属性 this.$store.getters["a/getNum"];//获取方法或计算属性 //方式二:通过辅助函数写法(常用) import {mapState,mapGetters} from "vuex"; computed:{ ...mapState("a",["msg"]),//a是nameSpace的命名空间,所以必须开启namespace才行 ...mapState(["a/msg"]),//这样获取不了,因为state的挂载方式不是这样挂载的 ...mapGetters(["a/getNum"]),//这样能获取,以为getters、mutations、actions的挂载方式 } //方式三:通过导入方法指定mapxxx的地址 import { createNamespacedHelpers } from 'vuex' const { mapState, mapActions } = createNamespacedHelpers('a') computed:{ ...mapState(["msg"]),//它会直接找a里的msg,因为上面设置了命名空间 }
-
-
辅助函数
mapState()获取的是大仓库state属性中的状态值
mapGetters()获取的是大仓库getters属性中的状态值
mapMutations()获取的是大仓库mutations属性中的方法
mapActions)获取的是大仓库actions属性中的方法
mapState()
-
在真实项目中我们不会使用
{{this.$store.state.count}}
来调用仓库中的状态值,以为这样每次页面渲染或打开页面都需要去大仓库中获取(无缓存) -
所以我们基于computed(有缓存)的优势,来获取仓库中的数据,这时就需要调用到vuex中内置的辅助函数:
mapState()
; -
第一步:导入
mapState
辅助函数-
//Home.js import mapState from "vuex";
-
-
第二步:在计算属性
computed
中配置mapState,mapState返回的是一个对象-
mapState(param):辅助函数的参数可以是对象或数组
- 对象可以自定义获取的状态值名,数组就是仓库中状态名是啥,我们调用就得用啥状态名
-
方式一:computed中只需要大仓库中的
mapState
-
//1、mapState函数中的参数是数组,会默认返回对应的num和age状态值,我们调用时也直接调用num age即可 computed:mapState(["num","age"]) //2、mapState函数中的参数是对象,会默认返回对应num和age状态值,并且赋值给调用方的私有属性n和a,我们调用时用n和a调用 computed:mapState({ n:"num", a:"age" })
-
-
方式二:computed中既有自己定义的计算属性,又用辅助函数获取的
-
computed:{ getData(){ return aaa; }, //因为mapState中获取的是对象,所以需要通过展开运算符将其展开 ...mapState( ["num","age"] ) }
-
-
注意:mapState获取的是对象,需要展开运算符展开
-
mapGetters()
mapGetters()获取的是大仓库getters属性中的状态值(必须是同步的方法)
-
vuex实例的getters属性相当于vue实例中的computed属性
-
第一步:在vuex实例中添加getters属性,并定义格式化方法:
-
//store/index.js getters:{ //第一个参数是当前vuex实例的state属性对象 //第二个参数是当前vuex实例的getters属性对象 addCount(state,getters){ return state.count++; } }
-
-
第二步:在调用方实例中导入,并引入
-
//Home.vue import mapGetter from "vuex";//导入mapGetter computed: { //方式一:直接在computed中调用:通过Vue公有属性中挂载的$store调用 addCount () { return this.$store.getters.addCount } //方式二:通过mapGetter调用 ...mapGetters(["addCount"]);//数组参数形式获取,不能改状态名 ...mapGetters({ add:"addCount";//对象形式获取,可以改状态名 }) }
-
mapMutations()
-
mapMutations()获取的是大仓库mutations属性中的状态值
-
**第一步:**在vuex中创建mutations属性
-
mutations: { addCount (state) { // 变更状态值 state.count++ }
-
-
第二步:在Home.vue中导入mapMutations并注册到实例methods上
-
export default { // ... methods: { ...mapMutations([ 'addCount', // 将 `this.increment()` 映射为 `this.$store.commit('increment')` ]), ...mapMutations({ add: 'addCount' // 将 `this.add()` 映射为 `this.$store.commit('increment')` }) } }
-
mapActions()
-
mapActions获取的是大仓库actions属性中的方法
-
第一步:在vuex实例中添加actions方法(必须是异步的):actions的作用就是将mutations里的同步方法异步化
-
//store/index.js actions: { //context是指向当前vuex实例的对象,也就是$store,所以能调用它上面的所有方法 increment (context) { context.commit('addCount') } }
-
-
第二步:在Home.vue中导入,并注册到自己身上
-
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'addCount', // 将 `this.addCount()` 映射为 `this.$store.dispatch('addCount')` // `mapActions` 也支持载荷: 'addCount' // 将 `this.addCount(amount)` 映射为 `this.$store.dispatch('addCount', amount)` ]), ...mapActions({ add: 'addCount' // 将 `this.add()` 映射为 `this.$store.dispatch('addCount')` }) } }
-
vuex缓存
-
问题:没有用缓存之前,我们每次打开页面都会发送请求
-
目标:应用vuex实现缓存,只要页面不刷新,不关闭,数据如果是null,我就发送请求,如果不是null就从vuex的缓存中拿数据
-
实现:
-
第一步:创建异步方法获取服务器数据,并把数据赋值给状态值
-
//index.js import Vue from 'vue' import Vuex from 'vuex' import moduleA from './moduleA/moduleA' import api from "@/api/index.js"; Vue.use(Vuex) //store实例 export default new Vuex.Store({ state: { // 第一步:list专门存放数据 list:null }, mutations: { // 第二步:修改list的值,如果请求成功就不为null了 changelist(state,payload){ state.list=payload; } }, actions: { //第三步:异步函数需要写在actions中 async getData(context){ let result=await api.getTaskList(); if(result.code===0){//返回数据成功 context.commit("changelist",result.list);//异步函数想修改state状态值,必须经过mutations } } }, modules: { a:moduleA } })
-
-
第二步:在页面加载之前,先判断是否有缓存,如果有直接用
-
//Three.vue <template> <div class="three"> {{this.$store.state.list}} </div> </template> <script> export default{ name:"Three", data(){ return{ } }, created(){ if(!this.$store.state.list){//只要list是null,表示没缓存,向服务器端发请求 this.getData(); } //否则直接调用list即可 }, methods:{ async getData(){ let result= await this.$api.getTaskList(); console.log(result); } } } </script> <style> </style>
-
-
vuex的使用步骤
-
第一步:安装
vue和vuex
模块包:$npm i vue vuex -S
-
第二步:导入vue和vuex
-
//为了防止导入的包太大,所以按需导入 // /store/index.js import vue from "vue"; import Vuex from "vuex";
-
-
第三步:Vue注册vuex并导出
-
// /store/index.js import vue from "vue"; import Vuex from "vuex"; //Vue注册Vuex Vue.use(Vuex) //创建vuex的实例 const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } }) //导出创建好的vuex实例 export default store;
-
-
第四步:在main.js中导入、挂载已经创建好的实例
-
//main.js import store from "@/store/index.js"; new Vue({ router, //store被挂载到了全局Vue实例的prototype上,任何实例都可以利用this.$store获取到store大仓库实例 store, render: h => h(App) }).$mount('#app')
-
-
第五步:任意组件可以调用修改仓库中的信息,但是想修改数据,都必须通知仓库(调用仓库mutations)中的方法,来实现页面数据与仓库数据的同步修改
-
面试题:能不能在界面上直接修改仓库中获取的数据:能!,但是修改的数据只是在页面上显示修改了,因为没有经过仓库,仓库中的数据实质上并没有修改,所以我们在工作中不能直接修改仓库中获取的值。
-
//Home.vue <div class="home"> {{this.$store.state.count}}//调用大仓库中的count <button @click="changeData">add</button>//修改仓库中的count </div> <script> methods:{ //Home.vue changeData(){ //使用store.commit来执行store中mutations中的方法 store.commit('increment') } } </script>
-
// /store/index.js const store = new Vuex.Store({ state: { //放到大仓库中的状态值,所有组件都可以用这个count count: 1000 }, //存放方法(同步) mutations: { //状态值自增的方法 increment (state) { state.count++ } } })
-