
参考资料:
1. vue-cli 脚手架
官方文档:https://v2.cn.vuejs.org/v2/guide/single-file-components.html
可以只是简单地使用 Babel,TypeScript,SCSS,PostCSS - 或者其他任何能够帮助你提高生产力的预处理器。如果搭配 vue-loader 使用 webpack,它也能为 CSS Modules 提供头等支持。
1.1 单文件组件
1.1.1 安装脚手架
-g 是全局安装,不论在哪个文件夹下均可。
1 2 3 4 5 6
| npm install -g @vue/cli
yarn global add @vue/cli
vue --version
|
1.1.2 创建项目
在具体要创建项目的文件夹,创建一个项目(未提及的均可默认):
1 2 3
| vue create my-project
vue ui
|







生成文件结构:

1.1.3 启动项目
启动命令在文件 package.json 中
1 2 3 4 5 6 7
| ... "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, ...
|
该标签可以修改,如
1 2 3 4 5 6 7 8
| ... "scripts": { "start": "vue-cli-service serve", "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, ...
|
启动命令:
1 2 3 4 5
| npm start npm run serve npm run build npm run lint
|
1.2 项目目录

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| . ├── node_modules/ ├── public/ │ ├── favicon.ico │ └── index.html ├── src/ │ ├── assets/ │ │ └── logo.png │ ├── components/ │ │ └── HelloWorld.vue │ ├── router/ │ │ └── index.js │ ├── store/ │ │ └── index.js │ ├── views/ │ │ ├── AboutView.vue │ │ └── HomeView.vue │ ├── App.vue │ └── main.js ├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── babel.config.js ├── jsconfig.json ├── lint-staged.config.js ├── package-lock.json ├── package.json ├── README.md └── vue.config.js
|
main.js
1 2 3 4 5 6 7 8 9 10 11 12
| import Vue from 'vue' import App from './App.vue'
Vue.config.productionTip = false
new Vue({ render: h => h(App) }).$mount('#app')
|
1.2.1 ESLint 语法检测处理
ESLint语法检测时报错,解决方案有以下几种: - 推荐 4.1
① 运行 npm run lint,会自动修复语法检测的内容
② vue.config.js (如果没有就手动创建出来的) 中配置 publicPath: './'
③ vscode自动修复eslint,安装 ESLint 插件,并启用。(不一定好使,跟vscode和eslint的版本有关系)
- 文件 >> 首选项 >> 设置 >> 用户 >> setting.json,加上以下配置
1 2 3
| "editor.codeActionsOnSave": { "source.fixAll": true }
|
④ 关闭eslint,两种方法(推荐第一种即可)
【推荐】在 vue.config.js(如果没有就手动创建出来的) 中 的module.exports 下 lintOnSave: false
- 在这种情况下,每次提交代码之前只需要执行一次
npm run lint 自动修复1次语法检测就可以提交了
.eslintrc 删除 '@vue/standard' (对于某个规则关闭,no-new: “off”)
- 或者,也可以通过设置让浏览器 overlay 同时显示警告和错误
1.3 单文件组件写法
常规注意事项:
最基本的单文件组件写法格式:
./App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| /* dom */ <template> <div> hello app-{{ myname }} <input type="text" v-model="mytext" /> <button @click="handleAdd">点击</button> <ul> <li v-for="item in datalist" :key="item"> {{ item }} </li> </ul> </div> </template>
/* js */ <script> // es6 导出规范 export default { data () { return { myname: 'jerry', mytext: '', datalist: [] } }, methods: { handleAdd () { console.log(this.mytext) this.datalist.push(this.mytext) } } } </script>
/* css: sass完全支持 */ <style lang="scss"> $width: 300px; ul { li { background: yellow; width: $width; } } </style>
|
1.4 单文件组件引入
全局引入 或 局部引入 按需选择其一。
./components/Navbar.vue
1 2 3 4 5
| <template> <div> hello,navbar. </div> </template>
|
./App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| /* dom */ <template> <div> ... <navbar></navbar> </div> </template>
/* js */ <script> // es6 导入 - 包括 Vue 对象也需要单独引入(哪个组件使用哪个引入) //import Vue from 'vue' import navbar from './components/Navbar.vue' // ①全局注册(导入的组件还是需要注册进来才能使用) //Vue.component('navbar', navbar)
// es6 导出规范 - babel(ES6==>ES5) export default { data () { return {} }, // ②局部注册(全局或局部按需选其一) components: { navbar // 名称相同因此可以简写,原 navbar: navbar }, methods: {} } </script>
/* css: sass完全支持 */ <style lang="scss"> ... </style>
|
1.5 单文件组件通信
./App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| /* dom */ <template> <div> hello app-{{ myname }} <input type="text" v-model="mytext" /> <button @click="handleAdd">点击</button> <ul> <li v-for="item in datalist" :key="item"> {{ item }} </li> </ul> <!-- 父传子、子传父、不同组件之间 通信 --> <navbar :myname="myname" :myright="false" @event="handleEvent"> <div>1111111111插槽替换</div> </navbar>
<sidebar v-show="isShow"></sidebar> </div> </template>
/* js */ <script> // es6 导入 - 包括 Vue 对象也需要单独引入(哪个组件使用哪个引入) // import Vue from 'vue' import navbar from './components/Navbar.vue' import sidebar from './components/Sidebar.vue' // 全局注册(导入的组件还是需要注册进来才能使用) // Vue.component('navbar', navbar)
// es6 导出规范 - babel(ES6==>ES5) export default { data () { return { myname: 'jerry', mytext: '', datalist: [], isShow: true } }, // 局部注册(全局或局部按需选其一) components: { navbar, sidebar }, // 名称相同因此可以简写,原 navbar: navbar methods: { handleAdd () { console.log(this.mytext) this.datalist.push(this.mytext) }, handleEvent() { this.isShow = !this.isShow } } } </script>
/* css: sass完全支持 */ <style lang="scss" scoped> $width: 300px; ul { li { background: red; width: $width; } } </style>
|
./components/Navbar.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <template> <div> <button @click="handleLeft">left</button> hello,navbar. - {{ myname }} <button v-show="myright">right</button> <slot></slot> </div> </template>
<script> export default { props: { myname: { type: String, default: '' }, myright: { type: Boolean, default: true } }, methods: { handleLeft() { // 通知父组件执行组件内的 event 事件函数 this.$emit("event") } } } </script>
|
./components/Sidebar.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <div> <ul> <li>001</li> <li>002</li> <li>003</li> </ul> </div> </template>
<style lang="scss" scoped> $width: 300px; ul { li { background: yellow; width: $width; } } </style>
|
1.6 单文件组件样式
scoped 在style标签中加,css样式组件内部生效
lang="scss" 在style标签中加,支持scss语法
1
| <style lang="scss" scoped> ... </style>
|
1.7 单文件组件生命周期
./components/Sidebar.vue - 如 mounted()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <template> <div> <ul> <li v-for="item in datalist" :key="item.filmId"> {{item.name}} </li> </ul> </div> </template>
<script> // 安装 axios 使用命令:cnpm i --save axios 安装成功后引入即可 import axios from 'axios' export default { data() { return { datalist: [] } }, mounted() { // fetch("./maizuo.json") // .then(res => res.json()) axios.get("./maizuo.json") .then(res => { // fetch 返回值在 第二个.then // console.log(res.data.films) // this.datalist = res.data.films // axios 返回值在 第一个.then 的 res.data 中 console.log(res.data) this.datalist = res.data.data.films }) } } </script>
<style lang="scss" scoped> $width: 300px; ul { li { background: yellow; width: $width; } } </style>
|
1.8 单文件组件-指令|过滤器
./App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| /* dom */ <template> <div> <!-- 验证指令和过滤器 --> <div v-hello>111111</div> <img :src="imgUrl | imgFilter"> </div> </template>
/* js */ <script> // es6 导入 - 包括 Vue 对象也需要单独引入(哪个组件使用哪个引入) import Vue from 'vue'
// 指令 - 支持 Vue.directive("hello", { inserted(el, binding) { // console.log("hello", el, binding) el.style.border = "1px solid gray" } })
// 过滤器 - 支持 Vue.filter("imgFilter", (path) => { return path + "?imageView2/1/w/128/h/180" })
// es6 导出规范 - babel(ES6==>ES5) export default { data () { return { myname: 'jerry', // imgUrl: "https://p0.pipi.cn/mediaplus/friday_image_fe/0fa3341477e6e3e327ce636483bf95940d84e.jpg?imageView2/1/w/128/h/180" imgUrl: "https://p0.pipi.cn/mediaplus/friday_image_fe/0fa3341477e6e3e327ce636483bf95940d84e.jpg" } } } </script>
|
1.9 单文件组件-swiper轮播
vue2对应vant2,安装命令:
1
| npm i swiper@5.x vue-awesome-swiper@4.1.1 -S
|
步骤:
1 2 3 4 5 6 7 8
| import { Swiper, SwiperSlide } from 'vue-awesome-swiper' import 'swiper/css/swiper.css'
components: { Swiper, SwiperSlide, },
|
完整参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| <template> <div> <div class="swiper"> <swiper :options="swiperOption"> <swiper-slide>Slide 1</swiper-slide> <swiper-slide>Slide 2</swiper-slide> <swiper-slide>Slide 3</swiper-slide> <swiper-slide>Slide 4</swiper-slide> <swiper-slide>Slide 5</swiper-slide> <swiper-slide>Slide 6</swiper-slide> <swiper-slide>Slide 7</swiper-slide> </swiper> </div> </div> </template>
<script> import { Swiper, SwiperSlide } from "vue-awesome-swiper"; import "swiper/css/swiper.css";
export default { name: "Main", components: { Swiper, SwiperSlide, }, data() { return { swiperOption: { spaceBetween: 30, slidesPerView: 5, // 一屏显示的slide个数 centeredSlides: true, // 居中的slide是否标记为active,默认是最左active,这样样式即可生效 slideToClickedSlide: true, // 点击的slide会居中 // loop: true,// 循环播放, 可有无限滚动效果,初始加载即是滚动后的效果 on: { // 该方法中的this都指代swiper本身 tap: function () { console.log("点击的位置", this.activeIndex); }, }, }, }; }, mounted() {}, methods: { test(e) { // 默认会$event对象 console.log(11, e); }, }, }; </script>
<style scoped> .swiper { width: 100%; height: 50px; bottom: 10px; /* 比如:在页面底部 */ position: absolute; background-color: darkred; }
.swiper-container { width: 100%; height: 100%; }
.swiper-slide { text-align: center; font-size: 18px; background: #fff;
/* Center slide text vertically */ display: -webkit-box; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-box-pack: center; -ms-flex-pack: center; -webkit-justify-content: center; justify-content: center; -webkit-box-align: center; -ms-flex-align: center; -webkit-align-items: center; align-items: center; transition: 300ms; transform: scale(0.5); }
.swiper-slide-active, .swiper-slide-duplicate-active { background-color: aqua; transform: scale(1); } </style>
|
效果:

2. 反向代理-解决跨域
vue.config.js 配置反向代理就可以解决跨域问题(让天下没有难跨的域)。
- devServer: {…} 可以指定端口号 port ,以及指定反向代理 proxy
如下请求:① 或 ② 均可
1 2 3 4 5 6 7 8 9 10 11 12
| axios .get( "/jerry/ajax/comingList?ci=73&token=&limit=10&optimus_uuid=424018A0DBF611F0B1298720294CD58A3B570872BF7C4455AF088EB790854A30&optimus_risk_level=71&optimus_code=10" ) .then((res) => { console.log(res.data); });
|
vue.config.js (①②分别对应axios请求的①②)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| module.exports = defineConfig({ transpileDependencies: true, lintOnSave: false,
devServer: { port: 8080, proxy: { '/jerry': { target: 'https://m.maoyan.com', changeOrigin: true, pathRewrite: { '^/jerry': '' } } } } })
|
3. 组件别名 @
@ webpack的别名,是 vue-cli 生成项目的 src 目录的绝对路径。
1 2 3 4 5 6
| import navBar from "./components/Navbar.vue"; import sideBar from "./components/Sidebar.vue";
import navBar from "@/components/Navbar.vue"; import sideBar from "@/components/Sidebar.vue";
|
也可以通过 vue.config.js 对目录进行别名配置(不一定会用的到,按需)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| module.exports = defineConfig({ transpileDependencies: true, lintOnSave: false,
configureWebpack: { resolve: { alias: { 'assets': '@/assets', 'components': '@/components', 'views': '@/views' } } } })
|