一、vue 脚手架
脚手架是一套已经包含核心功能和标准文件夹结构的半成品项目源代码,它的优点是标准化,极其便于协作,避免重复搭结构,降低学习成本。在今后所有的项目和新技术,基本都是在脚手架基础上开发的。
1. 脚手架搭建项目的步骤
(1)安装可以反复生成脚手架的工具(此步骤在搭建第一个项目时安装即可,后续不必再安)
a. 命令行 cmd 下设置淘宝镜像;
npm config set registry https://registry.npm.taobao.org
b. 安装可生成脚手架代码的命令行工具;
npm i -g @vue/cli
c. 当命令行窗口显示 [ + @vue/cli@版本号 ] 时说明安装成功。
(2)用工具反复为每个项目创建专门的脚手架结构
a. 先决定要把项目文件夹保存在哪个位置;
b. 然后在整个文件夹的位置,shift+ 鼠标右键打开 power shell 窗口,运行:vue create 自定义项目名;系统出现提示后按照以下过程进行选择:
1)? Please pick a preset:
Default ([Vue 2] babel, eslint)
Default (Vue 3) ([Vue 3] babel, eslint)
> Manually select features
2)? Check the features needed for your project:
( ) Choose Vue version //按空格切换选中/不选中
(*) Babel //将ES6翻译为ES5
( ) TypeScript
( ) Progressive Web App (PWA) Support
(*) Router //VueRouter,SPA应用的核心
(*) Vuex
(*) CSS Pre-processors //支持Scss语法
( ) Linter / Formatter //不要选,代码质量检查工具,要求过于严格
( ) Unit Testing
>( ) E2E Testing
3)? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) N
其实vue的路由有两种模式:
i. hash(#)模式: http://域名:端口号/#/相对路径
ii. history模式: http://域名:端口号/相对路径,无#,但需要专业的服务器端工程师配合,必须配置服务器端的首页重定向机制。
4)? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys)
> Sass/SCSS (with dart-sass)
Sass/SCSS (with node-sass)
Less
Stylus
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
命令行窗口显示 Successfully created project xzvue 说明安装成功。
2. 使用 vscode 打开并运行脚手架项目
(1)右键单击 package.json 文件,选择 "在集成终端中打开";
(2)在终端窗口中输入:npm run serve,等待后出现 App running at : - Local :http://localhost:8080/,如下:
(3)按住 Ctrl,点 local: 右侧的连接,即可自动打开浏览器。
需要注意 vue 采用的是热编译,修改后无需停止或重启项目,只要一修改,就会立刻自动重新编译,重新运行,自动在界面上显示新内容。
3. 脚手架文件夹结构(同SPA 4部分)
(1)唯一完整的 HTML 页面(一分为三)
a. HTML 页面基础结构放在 public/index.html 中;
b. <div id="#app"><router-view> 放在 src/App.vue 中;
c. new Vue({ router, ... }) 放在 src/main.js 中。
在运行时:
· src/main.js 中引入 src/App.vue 中的 HTML 内容;
import App from "./App.vue"
· src/main.js 中,将 new Vue() 和 App.vue 中的内容建立联系
· 运行时,唯一完整的 html 页面头部,自动添加引用 <script src="app.js">
· 最终 main.js、App.vue 以及 public 下的 index.html 是合并在一起运行的。
(2)页面组件:src/views/
脚手架规定,所有组件都必须创建为 .vue 文件。vue 文件专门包含一个组件的 HTML+CSS+JS 的新文件类型;
一个 .vue文件中标配包含3大部分:
· <template>专门编写组件的HTML内容</template>
若没有提示和颜色,安装 vscode vetur 插件即可。
· <script>专门包含组件对象</script>
vue 脚手架采用组件化开发,若一个组件 js 对象想要抛出让别人能够引用,必须使用:
export default { 组件内容 }
· <style>专门保存这个组件专属的 css 的区域</style>
(3)路由器对象:src/router/index.js
路由器对象包含2大部分,路由字典 routes 和路由器对象 router。在路由器对象中,每个文件都是一个独立的模块对象。模块之间可以直接引用。
a. 抛出
export default { 组件或对象的内容 }
b. 引入
import 自定义对象别名 from "相对路径"
(4)全局组件和子组件片段:src/components
所有组件都要创建为 .vue 文件,标准都要包含3部分(template、script、style)只要有 js 都要 export default{ } 抛出。
在创建全局组件时,先在 src/components/ 创建一个普通的子组件 .vue,再在 main.js 中 new Vue() 之前引入子组件 .vue,并将子组件对象转为全局组件;
import 子组件对象别名 from "./components/子组件.vue" Vue.component("标签名",子组件对象别名)
示例:封装页头组件过程;
(1)在 src/components/ 中新建 MyHeader.vue
(2)剪切 src/App.vue 中
<div id="nav">...</div>到MyHeader.vue中<template>中
<style>内#nav{...}及其子内容到MyHeader.vue中<style lang="scss">中
(3)src/main.js 中
import MyHeader from "./components/MyHeader.vue" ... Vue.component("my-header",MyHeader)
(4)src/App.vue 中 <router-view> 上方 <my-header></my-header>(为每个页面添加页头)
route 用于存放路由数据;
routers 是进行操作的工具;
4. 避免组件间样式冲突
有时候写在某个页面的样式,会覆盖其他页面中的样式。
这是因为虽然编写组件时是在各个 .vue 文件中分别编写的,但最终运行时脚手架会将所有 css 内容编译到网页的内部样式表中集中保存,所以不同组件中的选择器也会互相影响。
方法1:scoped
<style scoped> </style> <!-- 规定这个<style>内的所有选择器,只在当前组件内有效 -->
原理:
(1)为 css 中的选择器自动添加随机名称的属性选择器;
(2)为当前组件中的所有 HTML 元素自动添加与属性选择器同名的自定义属性;
(3)不同组件的 scoped 为每个组件添加的随机的属性名各不相同的属性选择器,即使有多个选择器也不会发生冲突;
(4)只有当前组件内部的 HTML 元素带有的自定义属性名才能匹配当前组件自己的 css 中的属性选择器。
但是此方法效率低,只对 <style> 内的 css 选择器有效,对于外部引入的 css 选择器无效,依然会发生冲突。
方法2:主动添加 class 名
今后每创建一个组件,都有一个唯一父元素,给唯一的父元素上加一个与当前组件名相同的class名(可避免重复且便于维护)。
当前组件内的所有 css 选择器,一律用这个唯一父级的 class 名开头;
5. 懒加载
单页面应用切换快,但是首屏加载极慢。因为脚手架 webpack 会默认把所有组件集中打包为一个巨大的 app.js 文件,在首屏一次性全部下载。
为解决这个问题就需要用到懒加载,即用户想看什么就只下载什么,用户暂时不想看的,没必要下载。
懒加载的两种方式:
(1)异步延迟加载(默认+常用)
即优先下载并显示首页内容,其它页面组件采用底层异步下载的方式,在不影响主屏下载速度的情况下,异步下载。既可以加快首屏加载的速度,又能享受单页面应用带来的好处。缺点是会偷跑流量。
Ⅰ.不要在 router/index.js 开头过早的引入除首页之外的其它页面组件,因为用 Import 引入的东西 vue 都会将其打包在 app.js 中,首屏下载。
Ⅱ.改造路由字典项(除首页之外的路由字典项),如下:
{ path:"/相对路径", component: ()=>import( /* webpackChunkName: "自定义js文件名" */ "../views/页面组件.vue" ) }
(2)彻底懒加载(了解)
如果用户不看哪些页面,就完全不下载,等到用户想看某个页面时,临时下载。
Ⅰ.先实现异步懒加载的两步,不提前引入+component 变成匿名箭头函数。
Ⅱ.配置脚手架,去掉 prefetch
a. 在脚手架根目录,创建 vue.config.js;
b. 在 vue.config.js 中添加以下固定代码:
module.exports={ chainWebpack:config=>{ config.plugins.delete("prefetch") //删除index.html开头的带有prefetch属性的link,不要异步下载暂时不需要的页面组件文件 }, }
c.重启 npm run serve。
二、举例:使用脚手架生成我的第一个Vue项目
项目完整的文件结构如下:
文件代码如下:
public/index.html
<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
src/App.vue
<template> <div id="app"> <my-header></my-header> <router-view /> </div> </template> <style lang="scss"> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } </style>
src/assets/css/home.css
.home>h1 { background-color: red; color: yellow; } .home>button { width: 300px; height: 50px; border-radius: 5px; background-color: aqua; border: 0px; font-size: 21px; color: white; font-weight: bolder; }
src/views/Home.vue(主页)
<template> <!-- 专门编写组件的HTML内容 --> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> <h1>我的第一个脚手架项目!</h1> <h2>我的名字:{{ uname }}</h2> <h3>ID:{{ uid }}</h3> <span>csdn</span><br /> <button @click="search">访问个人主页</button> </div> </template> <script> //专门包含组件对象 export default { data() { return { uname: "小马学前端", uid: "000001", }; }, methods: { search() { alert("欢迎访问!"); }, }, }; </script> <style> /* style专门保存这个组件专属的css的区域 */ /* 引入外部的CSS选择器 */ @import url(../assets/css/home.css); </style>
src/assets/css/about.css
.about>h1 { background-color: aqua; color: coral; }
src/views/About.vue(关于页)
<template> <div class="about"> <h1>This is an about page</h1> </div> </template> <style> /* 引入外部的css选择器 */ @import url(../assets/css/about.css); </style>
src/router/index.js(路由器对象)
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' Vue.use(VueRouter) const routes = [{ path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import( /* webpackChunkName: "about" */ '../views/About.vue') } ] const router = new VueRouter({ routes }) export default router
src/components/MyHeader.vue(页头组件)
<template> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> </template> <style lang = "scss"> #nav { padding: 30px; a { font-weight: bold; color: #2c3e50; &.router-link-exact-active { color: #42b983; } } } </style>
运行项目:
效果如下: