现实生活即使我们不甘,却又不得不去面对,平静的面对成功,坦然的面对挫折,豁达的面对属于自己的人生。心态好的人,是你最大的财富。
本期主要内容
- 组件化开发
- SPA
- 脚手架
- 脚手架结构:
- ES6模块化开发:
- 懒加载:
- 为整个脚手架项目配置统一的axios:3步
- 项目开发流程:
一. 组件化开发
-
什么是组件: 拥有专属的HTML+CSS+JS+数据的可重用的页面独立的功能区域
-
为什么: 重用
-
何时: 今后只要页面中有一个区域会被反复使用,都要先封装为组件,再反复使用组件
-
如何:
(1). 封装组件: 创建一个组件对象,添加到Vue大家庭中
Vue.component("组件名",{ //其实每个组件都是一个功能完整的小快递员,麻雀虽小五脏俱全! //所以,一个组件的内容和new Vue()的内容几乎完全一样 el:"#app", template:`HTML片段`, //模板,强调: 组件的HTML片段必须包含在一个唯一父元素内 data:{ 变量 }, data(){ //可反复调用,每次调用都返回一个新的保存数据的对象——老母鸡下蛋 return { //new Object() 变量: 初始值: ... : ... } }, //其余完全一样! methods:{ 函数 }, computed:{ 计算属性 }, mounted(){ ... } ... ... })
(2). 在页面中使用组件:vue中的组件其实就是一个可重复使用的自定义HTML标签而已
<组件名></组件名>
强调: 因为HTML不区分大小写,所以如果组件名(也就是将来的自定义标签名)包含多个英文单词时,不要用驼峰命名!应该用-分割多个单词!
-
原理:
(1). 当new Vue()扫描到不认识的自定义HTML标签时,会回vue家找有没有同名的组件对象
(2). 如果找到同名的组件对象,先把template中保存的HTML片段替换页面中组件名标签的位置
(3). 自动调用一次data(),为本次组件副本创建一个全新的模型对象
(4). 结果: 在当前组件这个小区域中就形成了一个缩微版的new Vue()对象和绑定关系。
-
示例: 创建一个计数器组件,并反复使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<script>
//想创建一个计数器组件,反复使用
Vue.component("my-counter",{
//组件要反复复制的HTML模板
//模板中将来哪里可能发生变化:
//本例中span的内容可能发生变化,所以用{{n}},初始为0
//模板中将来哪里可能触发事件:
//本例中button可能触发事件
template:`<div>
<button @click="minus">-</button>
<span>{{n}}</span>
<button @click="add">+</button>
</div>`,
//因为页面上需要1个变量
data(){
return {
n:0
}
},
//因为页面上需要两个事件处理函数
methods:{
add(){
this.n++;
},
minus(){
if(this.n>0){
this.n--;
}
}
}
})
</script>
</head>
<body>
<div id="app">
<!--页面上反复使用三次计数器组件: -->
<my-counter></my-counter>
<my-counter></my-counter>
<my-counter></my-counter>
</div>
<script>
new Vue({
el:"#app"
})
</script>
</body>
</html>
运行结果:
-
组件化开发:
(1). 什么是: 拿到一个网页之后,先将页面划分为多个组件区域,分头并行开发多个组件。最后再将所有组件拼成一个页面展现给用户。
(2). 为什么: 2个主要原因:
a. 可以多人并行开发一个页面——快!
b. 松耦合,一个人出错,不牵连大家!
(3). 何时: 今后所有使用前端框架开发的项目,全都采用组件化开发
(4). 如何:
a. 拿到页面先划分有几个组件: 2个原则
1). 区域划分 2). 是否重用b. 在页面之外创建独立的组件.js文件,包含组件的HTML+CSS+JS+数据
c. 创建一个完整的.html文件,将外部的组件.js文件内容都引入到.html文件中,在html文件中指定位置使用组价标签,将多个组件合为一个页面.
(5). 问题: 有些子组件,只有放在规定的父组件内才有效,才有意义。一旦出了父组件就没有意义了!
(6). 解决: 其实: vue中的组件大致分为三大类:
a. 根组件root: 一个页面只有一个,监控整个页面的组件 new Vue({ ... ... }) b. 全局组件: 可在任何位置反复使用的页面独立功能区域——没有限制Vue.component("组件名", { ... }) c. 子组件: 只能在某个指定的父组件内才能使用的小组件,2步: 1). 创建子组件对象: var 子组件名={ //和Vue.component中的格式完全一样! template:`HTML片段`, data(){ return { 变量 } }, ... ... } 强调: 因为子组件名是一个js变量,所以,不能用-分割多个单词,必须用驼峰命名 2). 在父组件中添加components属性来限制子组件只能在自己范围内使用 Vue.component("父组件",{ template:`HTML片段`, data(){ return { 变量 }}, ... ... components:{ 子组件对象名 , ... , ... } }) 强调: 但是,父组件中components会将驼峰命名的子组件名自动翻译为-分割多个单词,所以在父组件template中使用子组件标签时,依然要使用-分割 比如: components:{ todoAdd, todoList } 自动翻译 <todo-add> <todo-list>(7). 坑: 因为创建父组件时就需要子组件对象了,所以引入时,比如先引入子组件,再引入父组件!
(8). 示例: 使用组件化开发的方式开发待办事项列表的页面(暂时不含数据)
var todoItem={
template:`<li>
1. 吃饭 <a href="javascript:;">×</a>
</li>`
}
var todoList={
template:`<ul>
<todo-item></todo-item>
<todo-item></todo-item>
<todo-item></todo-item>
</ul>`,
//规定todoItem组件只能在当前todoList组件内才能使用,出了todoList组件外使用会报错
components:{ todoItem }
//自动翻译 <todo-item>
}
var todoAdd={
template:`<div>
<input><button>+</button>
</div>`
}
Vue.component(`todo`,{
template:`<div>
<h1>待办事项列表</h1>
<todo-add></todo-add>
<todo-list></todo-list>
</div>`,
//规定todoAdd和todoList两个组件只能在当前todo组件内才能使用,出了todo组件外使用会报错
components:{ todoAdd, todoList }
//自动翻译 <todo-add> <todo-list>
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="todo-item.js">
//var todoItem={ ... }) //孙子
</script>
<script src="todo-add.js">
//var todoAdd={ ... }) //儿子
</script>
<script src="todo-list.js">
//var todoList={ ... }) //儿子
</script>
<script src="todo.js">
//Vue.component("todo",{ ... }) //父亲
</script>
</head>
<body>
<div id="app">
<todo></todo>
<!-- <todo-item></todo-item>
报错: <todo-item> - did you register the component correctly
说明: 出了todo,就找不到todo-item了!只能在todo内使用!-->
</div>
<script>
new Vue({
el:"#app"
})
</script>
</body>
</html>
运行结果:
-
组件间传参:
(1). 问题: vue中子组件也无权直接使用父组件中的数据变量
(2). 解决: 父给子传值!
(3). 如何: 2步:
a. 父组件中:父将自己的变量通过:绑定的方式交给子组件
父组件对象: {
data(){
变量: 值
},
template:`<div>
... ...
<子组件 :自定义属性名="变量"></子组件>
</div>`
强烈建议: 子组件自定义属性名尽量和父组件中变量名保持一致!
b. 子组件中: 子组件从父组件放变量的自定义属性中取出父组件给的变量值
子组件对象:{
props:[ "自定义属性名", ... ]
data(){
return { 自己的变量 }
},
template:`<div>
... ...
//结果: 子组件中即可使用data()中自己的变量,也可以使用props中父组件给的变量。且props中变量的用法和data中自己变量的用法完全一样!只不过来源不同而已!
... ...
</div>`
}
(4). 示例: 使用父给子传参实现todo案例中任务列表和添加功能。
var todoItem={
//从父组件todoList给的两个自定义属性中取出父组件给的变量值
props:["task","i"],
//props中的变量和data中自己的变量用法一样,也可用于绑定和指令等。只不过props来源于外部,而data是内部定义的而已。
template:`<li>
{{i+1}}. {{task}} <a href="javascript:;">×</a>
</li>`
}
var todoList={
//从父组件给的自定义属性tasks中取出父组件给的tasks变量值
props:[ "tasks" ],
//props中的变量用法和自己data中变量用法完全一样,都可用于绑定、指令等。
template:`<ul>
<!--根据父组件中tasks数组中的元素个数,反复生成多个<todo-item>子组件-->
<todo-item v-for="(task,i) of tasks" :key="i" :task="task" :i="i"></todo-item>
</ul>`,
//规定todoItem组件只能在当前todoList组件内才能使用,出了todoList组件外使用会报错
components:{ todoItem }
//自动翻译 <todo-item>
}
var todoAdd={
props:["tasks"],
template:`<div>
<input v-model="task"><button @click="add">+</button>
</div>`,
data(){
return {
task:""
}
},
methods:{
add(){
this.tasks.push(this.task);
//在添加成功后,清空task变量值,也就自动清空了文本框中残留
this.task="";
}
}
}
Vue.component(`todo`,{
template:`<div>
<h1>待办事项列表</h1>
<todo-add :tasks="tasks"></todo-add>
<todo-list :tasks="tasks"></todo-list>
</div>`,
//因为三个子组件都需要访问一个任务数组
//所以在父组件中统一保存一个任务数组供所有子组件共同使用!
data(){
return {
tasks:["吃饭","睡觉","打亮亮"]
}
},
//规定todoAdd和todoList两个组件只能在当前todo组件内才能使用,出了todo组件外使用会报错
components:{ todoAdd, todoList }
//自动翻译 <todo-add> <todo-list>
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="todo-item.js">
//var todoItem={ ... }) //孙子
</script>
<script src="todo-add.js">
//var todoAdd={ ... }) //儿子
</script>
<script src="todo-list.js">
//var todoList={ ... }) //儿子
</script>
<script src="todo.js">
//Vue.component("todo",{ ... }) //父亲
</script>
</head>
<body>
<div id="app">
<todo></todo>
<!-- <todo-item></todo-item>
报错: <todo-item> - did you register the component correctly
说明: 出了todo,就找不到todo-item了!只能在todo内使用!-->
</div>
<script>
new Vue({
el:"#app"
})
</script>
</body>
</html>
运行结果:
二. SPA: Single Page Application
- 什么是单页面应用:整个应用程序只有一个唯一完成的HTML页面。其它所谓的"页面",其实都变成了组件。所谓的切换页面,其实切换的不是.html文件,而是一个html页面中的组件部分。
- 为什么:
-
单页面应用缺点: 首屏加载慢:
(1). 因为第一次请求时,就会把所有页面组件的内容都下载下来!
(2). 已经解决了:?
-
如何: 3大步
(1). 先创建一个唯一完成的HTML页面
a. 是一个基本的支持vue框架的页面结构
b. 如果有公共组件比如bootstrap.css, jquery.js和bootstrap.js,也要在唯一完整的HTML中引入
c. 在<div id="app">内必须写一个<router-view>元素为将来的页面组件占位
d. 之后还要引入所有页面组件和vue-router.js组件,以及保存VueRouter对象的router.js文件
e. new Vue()中除了el:之外,还要添加router成员
new Vue({
el:"#app",
router
})
(2). 为每个"页面"分别创建一个组件对象保存各自页面的内容: 强调: 每个"页面"组件,必须采用子组件对象方式创建
var 组件名={
组件内容
}
(3). 创建路由器对象根据地址栏的变化,自动切换显示不同的"页面"组件: 2步
a. 创建单独的router.js,保存路由字典和路由器对象
b. 创建路由字典数组:
//路由字典: 保存一组路径与组件间对应关系的数组
var routes=[
{ path:"/相对路径", component: 路径对应的组件对象名},
...
]
c. 创建路由器对象并将路由字典放入路由器对象中
var router=new VueRouter({ routes })
-
优化路由字典:
(1). 问题: 通常默认首页是不需要输入任何相对路径就可以访问的
解决: var routes=[ {path:"/", component: 首页组件} ...(2). 问题: 如果用户输入错误的路径,不能什么都不显示,应该显示404找不到网页
解决: 添加一个专门的404页面组件,并引入到页面中。并且在路由字典结尾添加: {path:"*", component: 404组件对象名} *表示除之前路径之外所有错误的路径,都导向404页面组件 -
公共页头部分: 一般创建为全局组件,并添加到之外,就不会被替换,而保证每个页面加载时都有!
问题: 有些页面(比如404)不想显示页头
解决: 页头不要放在唯一完整的HTML页面中,应该只放入那些需要页头的组件中!
-
路由跳转:
(1). 在HTML中写死的方式: 代替
<a><router-link to="/相对路径">文本</router-link>(2). 在js程序中也能用程序跳转:
固定套路: 没有为什么: this.$router.push("/相对路径")
-
路由传值:
(1). 修改路由字典中的相对路径,允许一个路径携带参数
{ path:"/相对路径/:变量名", component:组件名, props:true }
props: 让路径中的变量值自动进入下一个页面组件,成为props中的一个变量
(2). 上个页面跳转时可使用: /相对路径/变量值
(3). 在下个页面中用props:[ "变量名" ] 获取传过来的变量值
(4). 结果在下个页面组件中可以用变量名用作绑定或js程序都行!
(5). 坑: 一旦一个路径写了变量,则再用不带变量值的路径,就无法进入了!
比如: path:"/details/:lid"
将来: /details/5 可以进入
/details/10 可以进入
/details 禁止入内!导向404
- 示例: 制作一个单页面应用,包含首页和详情页
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<!--引入全局页头组件-->
<script src="myHeader.js"></script>
<!--引入所有页面组件-->
<script src="index.js">
//var index={ template:`首页内容` }
</script>
<script src="details.js">
//var details={ template:`详情页内容` }
</script>
<script src="notFound.js">
//var notFound={ template:`404:xxx` }
</script>
<!--引入SPA核心组件vue-router.js(官方)-->
<script src="js/vue-router.js"></script>
<!--引入我们自己创建的路由器和路由字典-->
<script src="router.js">
//var routes=[ 路由字典 ];
//var router=new VueRouter({ routes })
</script>
</head>
<body>
<div id="app">
<!-- <my-header></my-header> -->
<!--为将来要加载的页面组件占位-->
<router-view></router-view>
</div>
<script>
new Vue({
el:"#app",
//比如将引入的路由器对象添加new Vue()中,才能让new Vue()在扫描时认识<router-view>占位。
router
})
</script>
</body>
</html>
index.js
var index={
template:`<main>
<my-header></my-header>
<h1 style="color:lightGreen">这里是首页</h1>
<router-link to="/details/5">查看5号商品的详情</router-link><br/>
<button @click="toDetails">查看10号商品的详情</button>
</main>`,
methods:{
toDetails(){
this.$router.push("/details/10");
}
}
}
details.js
var details={
//接住地址栏中的lid变量的值(比如设置props为true才能这样用)
props:["lid"],
template:`<main>
<my-header></my-header>
<h1 style="color:orange">这里是{{lid}}号商品的详情</h1>
</main>`
}
notFound.js
var notFound={
template:`<h1 style="color:red">404:你迷路了~</h1>`
}
router.js
var routes=[
//默认首页
{path:"/", component:index},
//想让详情页可以带商品编号参数lid
{path:"/details/:lid", component:details, props:true},
//除以上路径之外,其余路径都导向404页面
{path:"*", component:notFound}
];
var router=new VueRouter({ routes });
myHeader.js
Vue.component("my-header",{
template:`<header>
<h1>这里是页头</h1>
<ul>
<li><router-link to="/">首页</router-link></li>
<li><router-link to="/details">详情页</router-link></li>
</ul>
<hr>
</header>`
})
三. 脚手架:
-
什么是脚手架代码:已经包含标准文件夹结构以及核心功能代码的半成品VUE框架项目
-
为什么: 统一标准化所有VUE项目的结构!
-
何时: 今后所有企业项目都在脚手架标准结构基础上继续开发
-
如何: 2步:
(1). 安装用于反复生成脚手架代码的命令行工具(老母鸡)
a. 测试当前环境是否安装了vue/cli
命令行: vue -V 看到: 'vue' 不是内部或外部命令,说明vue/cli工具没有安装b. 安装vue/cli
npm i -g @vue/cli 只要看到+ @vue/cli@4.4.5说明安装成功,版本号只要4.x以上都行c. 测试当前环境是否安装vue/cli
命令行: vue -V 看到: @vue/cli 4.4.5 说明安装成功!版本号只要4.x以上都行(2). 每做一个项目,都要用命令行工具生成一套脚手架代码(老母鸡下蛋)
a. 在要生成项目的文件夹,地址栏中输入cmd回车,在当前文件夹打开命令行
b. 运行vue create 项目名 按回车
1). ? Your connection to the default npm registry seems to be slow.Use https://registry.npm.taobao.org for faster installation? (Y/n) Y 2). ? Please pick a preset: (Use arrow keys) default (babel, eslint) > Manually select features 3). ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection) >(*) Babel 翻译: 脚手架代码中大量使用了ES6和ES7时髦的语法,大部分旧浏览器不支持!所以,最终交付给客户时,都要编译为等效的ES5代码,才能保证大部分浏览器都能正常使用! ( ) TypeScript VUE框架和react框架不主要使用ts,所以第三阶段不讲typescript。因为ng框架强制使用typescript,所以typescript第五阶段讲ng框架时再详细讲。 ( ) Progressive Web App (PWA) Support (*) Router 单页面应用的核心组件,必选 ( ) Vuex 以后必选! ( ) CSS Pre-processors 如果用less或sass才选 ( ) Linter / Formatter 代码规范和质量检查工具,就算程序没写错,功能可以正常执行,但是如果代码写的不规范或代码质量差,也会报错! ( ) Unit Testing ( ) E2E Testing 4). ? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) n i. 问题: SPA应用中默认使用#/路径方式作为前端项目客户端导航的地址区分方式 比如: #/ 默认首页 #/details 详情页 如果在一个特别长的网页中也想使用锚点地址做页面内导航,就会和SPA应用的#发生冲突! ii. 解决: 在new VueRouter({ mode: "history", routes }) 结果: SPA应用不再使用#/作为客户端导航地址 比如: / 默认首页 /details 详情页 iii. 问题: 浏览器懵逼了! 以前: 浏览器看到#/xxx 会发给前端的vue框架解析, 看到/xxx会发给后端服务器接口解析 现在: 都用/,浏览器会将所有/xxx都发给服务器端解析,不再发给vue框架解析,就会出错! iv. 解决: 今后只要想开启history模式去#,必须请服务器端工程师用特殊的重定向手段协助解决才行! v. 所以: 在达内学习时,不要开history模式,将来到了公司,再开history模式。 5). ? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys) In dedicated config files > In package.json 6). Save this as a preset for future projects? (y/N) n c. 看到以下内容,说明安装成功: 🎉 Successfully created project xzvue. 👉 Get started with the following commands: $ cd xzvue $ npm run serve(3). 脚手架代码已经是一套可以运行的网站代码了,包含了SPA应用三大部分内容和示例网页。用vscode运行:
a. 如果不用git管理代码,则可以删除.git隐藏文件夹:
1). 在操作系统文件夹窗口,选顶部菜单: 查看->选项->查看->选中 显示隐藏的文件、文件夹和驱动器,点应用 2). 进入刚创建的项目文件夹,删除.git文件夹b. 用vscode打开刚刚命令行创建的项目文件夹
c. 右键单击package.json文件,选择"在终端中打开"
d. 当弹出终端窗口(稍等),看到>,输入npm run serve
1). DONE Compiled successfully in 3163ms 会编译/翻译脚手架中时髦的代码为ES代码,并压缩代码。 2). App running at: - Local: http://localhost:8080/ 启动一个简化版的服务器,临时保存脚手架项目中的网页,让开发人员可以在本地调试网页功能 从此,再不会用live server —— 退出历史舞台! 今后,只要是vue脚手架项目都用npm run serve运行! 3). 按住ctrl,点终端中Local后的连接,就可打开示例页面e. 你不用每次都反复运行npm run serve:
(1). npm run serve是热编译,只要代码一修改,一保存,自动重新编译!无需手动重新运行命令! (2). 已经打开的页面无需刷新,就自动换成修改后的页面了! -
(选装)安装vetur插件: 2个办法:
(1). 有外网: 点vscode左侧最下方“扩展”按钮,文本框输入octref.vetur,点安装
- 小程序:微信搜索web问题速查
四. 脚手架结构:
-
回顾: SPA应用3步+1步:
(1). 创建一个唯一完整的HTML页面,包含
a. 占位
b. new Vue({ ..., router })
(2). 为每个"页面"都创建一个组件对象/文件
(3). 在专门的router.js文件中创建路由器对象和路由字典
(4). 如果有共用的页头,会创建全局组件,在需要的页面组件中引入
-
脚手架项目结构就是SPA应用标准结构!只不过有的划分的更细致,有的放入专门的文件夹中。——脚手架项目结构绝不是新知识!
(1). 也有一个唯一完整的HTML页面: 但是被一分为三
a. 基础HTML部分,保留在了index.html中
public文件夹/ 将来做项目时 css文件夹/ 包含不是自己写的第三方的压缩过的css文件,比如bootstrap.min,css js文件夹/ 包含不是自己写的第三方的压缩过的js文件,比如: jquery-1.11.3.min.js bootstrap.min.js imgs文件夹/ 包含网站所需的所有图片 index.html 唯一完整的HTML页面
b. <div id="app">
<router-view>
被单独放在src/App.vue文件中
c. new Vue() 也被单独放在src/main.js文件中
d. 将来运行时,先会用App.vue中的
```
<div id="app"><router-view>自动代替index.html中的空的<div id="app">,并用main.js中的new Vue()加载router,扫描index.html中的<div id="app">
e. public/index.html + src/App.vue + src/main.js 合起来等效于昨天SPA中的index.html
```
(2). 也要为每个“页面”分别创建组件对象/文件,只不过
a. 所有页面组件的文件都集中放在src/views文件夹中,
b. 且每个页面都是一个.vue文件,而不是一个.js文件。每个.vue文件包含三部分:
1). <template></template>内,包含页面组件的HTML片段
2). <script></script>内,包含页面组件的对象 —— 和昨天讲的页面组件对象相比,除了没有template属性之外,其余完全一样!
3). <style></style>内,包含这个页面组件所需的所有css定义。
c. 运行时: 也会根据地址栏变化,将对应组件的<template>中的html代替index.html中的<router-view>位置。用<script>中页面组件对象监控<template>中HTML内容的变化实现vue绑定和交互功能。
(3). 也会在专门的router.js文件中创建路由字典和路由器对象: 只不过:
a. 必须放在src/router文件夹/index.js
b. 内容几乎没变!
c. 除了增加了懒加载功能(下午讲)
(4). 如果有公共的页头组件,也应该创建为全局组件:有点变化! 2步
a. 在src/components文件夹下,新建.vue文件保存全局组件的<template>+<script>+<style>
组件们
问题: 暂时只是一个普通的子组件对象,还不是Vue家的全局组件
b. 在main.js中,new Vue()之前,2步:
1). 引入src/components/全局组件.vue文件,
2). 再将引入的全局组件对象用Vue.component()函数转化成一个Vue大家庭中的全局组件。
c. 结果: 在项目任何一个组件中的<template>中使用<组件标签名>来引用全局组件
- 样式冲突:
(1). 问题: 所有.vue中的<style>中的css样式最终会被编译到一个大的.css文件中集中保存,默认所有页面其实是共用这批样式的!极容易造成污染!
(2). 解决: 如何避免组件间样式冲突: 高频笔试题
a. 好的解决办法: 2步:
1). 在创建组件时,就为组件的唯一父元素定义一个专门的class名!跟别的组件都不一样!
2). 从此一个组件下的所有css选择器,都要以这个组件的统一class名开头
b. 偷懒的,不一定总是有效的方法: 1步
1). <style scoped>...</style>
2). scoped属性自动保证当前组件内的样式一定和别的组件的样式不冲突!
3). 原理:
i. scoped会给当前组件随机添加一个自定义属性
<template>
<div afasdfsdaf >
... ...
ii. 然后自动给<style>中每个选择器前加上这个自定义属性选择器
<style>
[afasdfsdaf]>xxx{ ... }
[afasdfsdaf]>xxx{ ... }
iii. 因为不同组件随机生成的自定义属性名不同,所以,也可避免组件间样式冲突
iv. 问题: 随机生成的自定义属性名没有意义,不可维护。不如自己主动定义的class名好用。
五. ES6模块化开发:
-
什么是模块: 封装一个事物的属性和功能的对象
-
在Vue脚手架中,每个.vue文件默认也都是一个模块对象
-
一个模块对象可以随意被其它的模块或文件引入,如果一个模块中想使用另一个模块的内容和功能,都用import引入
import 自定义对象名 from "相对路径/文件名.vue"
结果: 将路径所指的.vue文件中的内容,打包为一个对象,引入当前文件中。
强调: 不管原来模块叫什么名字,from前的对象名是可以任意自定义的!
-
抛出模块对象:
(1). .vue文件在不包含js内容时,默认就是一个模块对象,可被别人import引入
(2). 如果.vue文件中包含了组件对象(js代码),则必须用export default { ... 组件js内容 ...}抛出,外人才能用import引入使用
六. 懒加载:
-
问题: 旧单页面应用中,首屏加载时,只能一次性将所有页面组件,打包为一个大的js文件,下载下来。不管用户是否会看除首页之外的其它页面,都会全部下载所有页面内容。——首屏加载极慢,且不划算
-
解决: 懒加载
-
懒加载: 首屏只加载首页的内容(懒),之后,每请求一个新页面,才临时下载新页面组件的内容。
-
好处: 首屏加载快
-
缺点: 后续页面加载稍慢!
-
其实: 2种懒加载:
(1). 异步延迟下载:当加载首页组件内容时,同时在底层发送异步请求,在不影响当前页面使用的情况下,悄悄的下载其余页面的内容
a. 优点: 当用户访问下个页面时,可能下个页面的组件已经提前异步下载好了!不影响后续页面的加载速度
b. 缺点: 偷跑流量!在用户不知道的情况下,多下载了内容。
c. 如何: 只在router/index.js中
1). 除首页之外的其它页面组件,不要提前import引入! 2). 路由字典中,除首页之外的其它页面,都可以采用: { path: '/about', ///* webpackChunkName: "将来独立下载的js文件名" */不能删除,因为这是在为将来独立打包的js文件自定义文件名。 component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') //结果: 不再把About.vue的内容和大js打包在一起。而是单独生成一个about.js文件 //下载时,异步单独下载about.js文件 }(2). 完全懒加载:只有当用户确实访问到这个页面时才动态加载这个页面的js。如果用户不访问。则永远不加载该页面.js
a. 优点: 不会偷跑流量
b. 缺点: 后续页面加载稍微慢
c. 如何:
1). 以上两步还是要做 2). 多做一件事: 在脚手架项目根目录创建一个文件vue.config.js,在其中添加如下代码: module.exports={ chainWebpack:config=>{ config.plugins.delete("prefetch") //取消异步延迟下载 } }d. 结果: 所有懒加载的页面.js文件都不会提前异步延迟下载。只有用户访问这个页面对应的地址时,才临时下载页面组件.js。
七. 为整个脚手架项目配置统一的axios:3步
-
安装axios: npm i -save axios
看到: + axios@0.19.2 说明安装完成
结果: node_modules文件夹中多出一个axios文件夹
-
引入并配置axios模块: 在main.js中, new Vue()之前
import axios from"axios"//引入node_modules中的模块,什么路径/都不用加!
//配置服务端基础地质:
axios.defaults.baseURL="http://xzserver.applinzi.com"
-
将配置好的axios对象放到Vue的原型对象中!
(1). 问题: 我们希望在所有页面组件或子组件或全局组件中都能随处使用axios对象发送ajax请求
(2). 原理: 其实,无论根组件newVue(),还是全局组件,还是页面组件,还是子组件,底层都是Vue类型的子对象。只不过我们看不见new而已!——信任!
(3). 解决: 所有vue的孩子共用的东西,都要放在Vue的原型对象中 //强行给Vue.prototype添加一个axios属性,值为配置好的axios对象 Vue.prototype.axios=axios;
-
结果: 所有组件中,都可用this.axios发送ajax请求!
八. 项目开发流程:
-
先在public文件夹中准备好第三方的css和js,以及项目要用的所有图片,并在index.html页面顶部引入第三方的css和js
-
如果有整个项目每个页面都需要的基础的css重置代码,应该放在App.vue中的style中!
因为App.vue相当于所有页面的一个外壳!
所有页面将来加载时,都会替换App.vue中
<router-view>成为App.vue中的一部分所有公共的css代码只要放在App.vue中,所有页面将来都会共用! -
在src/views文件夹下为每个页面创建独立的.vue文件:
<template>
这个页面的HTML片段(唯一父元素!)
</template>
<script>
export default {
就是以前的页面组件对象, 当前页面所需的所有变量,函数,ajax请求等!
props:[],
data(){
return {
变量
}
},
methods:{
函数
},
computed:{
计算属性
},
mounted(){
this.axios.get(...).then(result=>{ ... })
}
}
</script>
<style scoped>
当前页面所需的css
</style>
-
在src/router/index.js中,修改路由字典,换成我们网页的名称和路径!
(1). 引入我们自己页面的模块对象
(2). 修改routes中的路由字典
-
先在src/components文件夹中创建页头组件.vue文件,还要在main.js中引入页头组件,并转化为全局组件。最后在需要加载页头的位置使用页头组件标签加载页头内容即可。
-
在每个页面组件中发送axios请求,获取数据,绑定页面