1. 插槽
1.1 插槽的基本使用
组件的插槽:
-
组件的插槽也是为了让我们封装的组件更加具有扩展性。
-
让使用者可以决定组件内部的一些内容到底展示什么。
定义插槽的步骤
-
在组件中使用一个特殊的元素
<slot></slot>
可以为组件开启一个插槽。 -
该插槽插入什么内容取决于父组件如何使用。

<div id="app">
<cpn><span>用户</span></cpn>
<hr>
<cpn></cpn>
<hr>
<cpn>
<span>更多</span>
<span>收藏</span>
</cpn>
</div>
<template id="cpn">
<div>
<span>返回</span>
<h1>我是子组件</h1>
<slot>
<!-- 设置一个默认的span -->
<span>登录</span>
</slot>
</div>
</template>
<script src="../../js/vue.js"></script>
/*
* 1. 插槽的基本使用 <slot></slot>
* 2. 插槽的默认值 <slot></slot>
* 3. 如果有多个值同时放入到插槽中进行替换的时候,一起作为替换元素。
* */
const app = new Vue({
el: '#app',
data: {},
components: {
'cpn': {
template: '#cpn'
}
}
});
1.2 具名插槽
- 定义具名插槽,需要在
slot
标签中使用name
属性标识该插槽的名称,在使用时在具体的标签中使用slot
属性指定需要替换的插槽的名称。

<div id="app">
<cpn>
<span slot="center">我是标题</span>
</cpn>
<hr>
<cpn>
<span slot="left">返回</span>
</cpn>
<hr>
<cpn>
<span slot="left">返回</span>
<span slot="center">我是标题</span>
<span slot="right">用户</span>
</cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script src="../../js/vue.js"></script>
const app = new Vue({
el: '#app',
data: {},
components: {
'cpn': {
template: '#cpn'
}
}
});
1.3 编译作用域

<div id="app">
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<h1>我是子组件</h1>
<span>6666</span>
<!-- 这里的isShow是子组件中的所以下面是不会显示的 -->
<span v-show="isShow">我会显示吗?</span>
</div>
</template>
<script src="../../js/vue.js"></script>
const app = new Vue({
el: '#app',
data: {
isShow: true
},
components: {
'cpn': {
template: '#cpn',
data() {
return {
isShow: false
}
}
}
}
});
1.4 作用域插槽
- 当子组件中的数据使用了默认的显示方式,但是父组件希望拿到子组件的数据在其基础上修改显示方式,就可以使用作用域插槽。
作用域插槽的使用步骤
- 在子组件中定义一个插槽,可以指定一种默认的显示方式。并在插槽上使用
自定义属性
绑定一个子组件的数据,传递给父组件。

- 父组件使用
template
标签 和slot-scope
属性获取来自子组件的数据,在slot-scope
中指定一个属性接收数据。

<div id="app">
<!-- 默认以列表方式显示 -->
<cpn></cpn>
<!-- 这里希望使用分割符方式进行展示,但是如何拿到子组件的数据? -->
<cpn>
<!-- 父组件需要使用 template 获取子组件传递的数据 -->
<template slot-scope="cpnSlot">
<span>{{cpnSlot.data.join(' - ')}}</span>
</template>
</cpn>
<cpn>
<!-- 父组件展示列表时希望使用 * 分割 -->
<template slot-scope="myData">
<span>{{myData.data.join(' * ')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- :data="pLanguage" 自定义一个属性将子组件的数据传递给父组件 -->
<slot :data="pLanguage">
<ul>
<!-- 默认是使用列表方式进行展示 -->
<li v-for="item in pLanguage">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../../js/vue.js"></script>
/* 作用域插槽是父组件替换插槽的标签,但是内容由子组件提供 */
/* 问题:如何在父组件中拿到子组件中的数据 */
const app = new Vue({
el: '#app',
data: {},
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguage: ['JavaScript', 'Java', 'C++', 'C#']
};
}
}
}
});
2. 前端模块化开发
2.1 JavaScript原始功能
存在的问题
-
客户端需要完成的事情越来越多,代码量也是与日俱增。
-
为了应对代码量的剧增,我们通常会将代码组织在多个js文件中,进行维护。
-
但是这种维护方式,依然不能避免一些灾难性的问题。
如下面的代码
index.html
<body>
<script src="../js/xiaoming.js"></script>
<script src="../js/xiaohong.js"></script>
<script src="../js/tiancai.js"></script>
</body>
xiaoming.js
// 小明的文件
var name = '小明';
var age = 23;
function sum(a, b) {
return a + b;
}
var flag = true;
if (flag) {
console.log(sum(12, 36));
}
xiaohong.js
// 小红的js文件
var name = '小红';
console.log(name);
var flag = false;
tiancai.js
if (flag) {
console.log('我真是个天才');
}
- 上面代码由于调用顺序问题,和变量名重名问题,导致后面的代码修改了前面的变量,出现问题。
2.2 解决方案:匿名函数
- 我们可以使用匿名函数来解决方面的重名问题,在
xiaoming.js
文件中。

3. webpack
对打包的理解
-
理解了webpack可以帮助我们进行模块化,并且处理模块间的各种复杂关系后,打包的概念就非常好理解了。
-
就是将
webpack
中的各种资源模块进行打包合并成一个或多个包(Bundle
)。 -
并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将
scss
转成css
,将ES6
语法转成ES5
语法,将TypeScript
转成JavaScript
等等操作。
3.1 webpack 的介绍和安装
-
webpack
要正常运行必须依赖于node
。node
为了可以正常执行很多代码,必须包含各种包。 -
查看自己的
node
版本:
node -v 或者 node --version
- 全局安装
webpack
(这里我先指定版本号3.6.0
,因为vue cli2
依赖该版本)。
npm install webpack@3.6.0 -g
- 局部安装webpack(后续才需要)。
cd 对应目录
npm install webpack@3.6.0 --save-dev
为什么全局安装后,还需要局部安装呢?
-
在终端直接执行
webpack
命令,使用的全局安装的webpack
。 -
当在
package.json
中定义了scripts
时,其中包含了webpack
命令,那么使用的是局部webpack
。
3.2 webpack 的基本使用
-
在项目文件夹下创建
dist
和src
文件夹。dist
文件夹用于存放的是打包完成的文件。src
存放的是打包之前的文件。 -
场景 : 创建
main.js
和mathUtils.js
、info.js
三个文件。在项目下创建index.html
文件。下面分别使用CommonJs
模块化 和ES6
模块化。最终使用webpack 打包
。 -
main.js
分别导入info.js
和mathUtils.js
的模块。
/* CommonJS的方式 */
const {add, mul} = require('./mathUtils.js');
console.log(add(20, 30));
console.log(mul(100, 10));
/* 使用ES6的方式 */
import {age, height, name} from './info.js';
console.log(name);
console.log(age);
console.log(height);
/*
webpack 打包命令 :
1. 切换到当前目录 ;
2. 使用 webpack ./src/main.js ./dist/bundle.js 进行打包;
*/
-
info.js
使用ES6
模块化方式。
export const name = '张三';
export const age = 23;
export const height = 1.88;
-
mathUtils.js
使用CommonJs
模块化方式。
function add(a, b) {
return a + b;
}
function mul(a, b) {
return a * b;
}
/* CommonJs的方式 */
module.exports = {
add,
mul
};
- 使用命令进行打包操作:
webpack ./src/main.js ./dist/bundle.js
。
3.3 webpack.config.js配置和package.json配置
webpack.config.js 文件
- 在项目下创建一个
webpack.config.js
的文件,定义打包的对象。

-
上面文件定义完成之后便可以在项目路径下使用
webpack
命令直接打包了。 -
初始化
package.json
文件配置命令映射。使用npm init
命令初始化package.json
文件。

-
如上配置之后可以使用
npm run build
打包项目。 -
但是此时使用打包的
webpack
是全局安装的webpack
但是在之后可能全局webpack
版本和项目使用的webpack
版本不一致的情况,此时就需要在项目的目录下自己安装一个本地(局部)webpack
。使用命令npm install webpack@3.6.0 --save-dev
或cnpm install webpack@3.6.0 --save-dev
但是不建议使用cnpm
,我试过可能因为下载太快,我使用webstorm
加载过程中非常卡 。

3.4 什么是loader?
-
webpack
可以使用 loader 来预处理文件。这允许你打包除JavaScript
之外的任何静态资源。loader
可以将所有类型的文件转换为webpack
能够处理的有效模块,然后你就可以利用webpack
的打包能力,对它们进行处理。本质上,webpack loader
将所有类型的文件,转换为应用程序的依赖图(和最终的bundle
)可以直接引用的模块。 -
在我们之前的实例中,我们主要是用
webpack
来处理我们写的js代码,并且webpack
会自动处理js
之间相关的依赖,但是,在开发中我们不仅仅有基本的js
代码处理,我们也需要加载css
、图片,也包括一些高级的将ES6
转成ES5
代码,将TypeScript
转成ES5
代码,将scss
、less
转成css
,将.jsx
、.vue
文件转成js
文件等等。对于webpack
本身的能力来说,对于这些转化是不支持的。那怎么办呢?给webpack
扩展对应的loader
就可以啦。
3.5 loader使用过程:
-
步骤一:通过
npm
安装需要使用的loader
。 -
步骤二:在
webpack.config.js
中的modules
关键字下进行配置。 -
大部分
loader
我们都可以在webpack
的中文网中找到。
3.6 使用 css-loader 和 style-loader 的场景
- 编写一个样式文件
noemal.css
文件,在main.js
(入口文件)中进行使用require()
引入。
require('./css/normal.css');
- 此时如果使用
nom run build
打包的话将会出现下面一个问题。

- 查看官方文档,使用命令安装
css-loader
此时未指定版本默认是最新版本。
npm install --save-dev css-loader
- 安装完成之后在
webpack.config.js
中进行配置:

- 配置完成之后,发现尚未可??? 原来是还缺少了一个
loader
style-loader
。style-loader
将模块的导出作为样式添加到DOM
中。安装style-loader
。
npm install style-loader --save-dev
- 安装配置完成还有个问题 ??? ,,,
(node:58300) UnhandledPromiseRejectionWarning: TypeError: this.getResolve is not a function
。 百度一下发现,是我的版本太高了,我按照提示将package.json
下的依赖版本进行修改,重新使用npm install
对依赖进行安装之后。终于可以了。

3.7 webpack 对 less 文件的处理
-
在开发过程中我们大多数时候会使用到
less
语法,所以webpack
需要提供对less
的支持。 -
安装
less-loader
,但是less-loader
需要less
支持。同时需要安装less
。
npm install --save-dev less-loader less // 这样安装的是最新版的,后面会出问题 可以后面修改版本或者现在修改版本
npm install --save-dev less-loader@4.1.0 less@4.1.0
- 安装完成之后在
webpack.config.js
中配置less-loader
:
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
}

3.8 webpack对图片文件的处理案例
-
准备两张图片,大小分别一大一小。之后可以设置文件大小一个分界线。
-
在样式中设置背景图片:该样式文件已经在
main.js
中引入,到时候打包将会将样式文件打包为一个模块。
body {
/*background-color: #f00;*/
background: url(../images/green-logo.png) no-repeat;
background-size: cover;
}
body {
/*background-color: #f00;*/
background: url(../images/green-logo-mini.png) no-repeat;
background-size: cover;
}
- 使用
npm run build
进行打包,发现需要安装适当的loader
。

npm install --save-dev url-loader
- 安装完成之后在
webpack.config.js
文件中进行配置:options: {}
中配置的是打包的一些属性。limit
相当于文件大小的分界线,如果超出该分界线是需要file-loader
的支持的。
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
/* 当图片小于指定的尺寸的时候回将其转换为base64位的图片 */
limit: 10240
}
}
]
}


- 安装
file-loader
,npm install --save-dev file-loader
。
url-loader中options对象的属性 name
-
name
属性:name: 'img/[name].[hash:8].[ext]'
。
img
:文件要打包到的文件夹;
name
:获取图片原来的名字,放在该位置;
hash:8
:为了防止图片名称冲突,依然使用hash
,但是我们只保留8
位;
ext
:使用图片原来的扩展名。
3.9 babel 对 ES6 语法的处理 babel-loader
未使用
babel-loader
转换打包,还存在const
关键字声明变量。

- 使用
babel
将ES6
转为ES5
。
-
安装
babel-loader
:npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
。 -
在
web.config.js
中配置babel-loader
。exclude
属性用于排除某些文件夹,不对其进行转换。
{
test: /\.js$/,
/* exclude 是排除的意思 */
/* include 是包含的意思 */
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}

3.10 webpack配置Vue的过程
- 使用命令
npm install --save vue
安装Vue
,在main.js
中导入Vue
。
// 1. 导入 vue
import Vue from 'vue';
- 使用
Vue
输出一段文字。
const app = new Vue({
el: '#app',
data: {
message: 'Hello webpack!'
}
});
- 启动运行时发现出现下面的问题,是因为在
Vue
打包中有很多的版本其中有两个是runtime-only
和runtime-compiler
。

解决:在webpack.config.js文件中module同层级下配置如下代码
resolve:{
alias:{
'vue$':'vue/dist/vue.esm.js'
}
}

Vue打包的两个版本
-
runtime-only
: 代码中,不可以有任何的template
。 -
runtime-compiler
: 代码中可以有template
,因为compiler
可以用于编译template
。
3.11 使用创建Vue
时 template
和 el
的关系

-
在前面的
Vue
实例中,我们定义了el
属性,用于和index.html
中的#app
进行绑定,让Vue
实例之后可以管理它其中的内容。 -
上面我们将页面中
<div id="app"></div>
包裹的代码删除,在main.js
中使用template
编写相应的模板进行替换。
3.12 Vue的终极使用方案
使用 JS
方式文件分离组件

- 但是使用这种方式还是未将
template
和js
代码相分离开。
创建 Vue
文件的方式分离组件
- 需要提前安装一个
loader
vue-loader
和vue-template-compiler
。
npm install vue-loader vue-template-compiler --save-dev
- 在
webpack.config.js
中配置vue-loader
。
{
test: /\.vue$/,
use: {
loader: 'vue-loader'
}
}

- 创建一个
Vue component
:
<template>
<!-- 模板相关 -->
<div>
<h2>使用 JS 方式分离 template </h2>
<h2>{{message}}</h2>
<button @click="btnClick">点我啊</button>
</div>
</template>
<script>
export default {
name: "app"
/* js相关 */,
data() {
return {
message: 'Hello webpack! i`m template 666 '
}
},
methods: {
btnClick() {
console.log('你点了我');
}
}
};
</script>
<style scoped>
/* 样式相关 */
h2 {
color: #00f !important;
}
</style>
- 注意
vue-loader
的版本问题。改为13.0.0
。


3.13 认识 plugin
为我们的代码添加一个版权声明插件 BannerPlugin
- 在
webpack.config.js
中配置。


打包html的plugin html-webpack-plugin


- 安装
html-webpack-plugin
插件:
npm install html-webpack-plugin --save-dev
- 配置插件并指定打包模板:

- 可能会出现版本问题 :在
package.json
中修改版本信息

"html-webpack-plugin": "^3.0.0"
npm install
压缩JS代码 UglifyjsWebpackPlugin
-
UglifyjsWebpackPlugin
, 丑化代码,压缩代码插件。
- 安装插件,为开发时插件。
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
- 在
plugins
中配置插件 :

3.14 使用webpack搭建本地服务器
- 安装
webpack-dev-server
:
npm install --save-dev webpack-dev-server@2.9.3
- 配置
devServer
:

- 启动有两种方式: 第一种使用在
package.json
中的命令的方式,第二种方式使用node_modules
中的命令的方式。

// 第一种方式 由于在 package.json中配置了script命令所以可以直接使用如下命令启动
npm run dev
3.15 webpack 中配置文件的抽离
-
创建一个
build
文件夹,在里面创建base.config.js
和prod.config.js
、dev.config.js
。 -
将公共的配置都抽取到
base.config.js
中。将开发环境的配置配置到dev.config.js
中 ,将生产环境的配置配置到peod.config.js
中。
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js',
/* 有关url的都会加上dist路径 */
// publicPath: 'dist/'
},
module: {
rules: [
{
test: /\.css$/,
/* css-loader 只负责将css文件进行加载 */
/* style-loader 负责将样式添加到DOM中 */
/* loader 从右向左读 */
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
/* 当图片小于指定的尺寸的时候回将其转换为base64位的图片 */
limit: 10240,
name: 'img/[name].[hash:8].[ext]'
}
}
]
},
{
test: /\.js$/,
/* exclude 是排除的意思 */
/* include 是包含的意思 */
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
},
{
test: /\.vue$/,
use: {
loader: 'vue-loader'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins: [
new webpack.BannerPlugin('最终版权归我所有!'),
new HtmlWebpackPlugin({
template: 'index.html'
})
]
};
- 安装合并插件,将他们分别进行合并。
npm install webpack-merge@3.0.0 --save-dev
- 将
base.config.js
与prod.config.js
合并:
const UglifyJsWebpackPlugin = require('uglifyjs-webpack-plugin');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config')
/* 合并 基本的配置 + 生产时依赖 */
module.exports = webpackMerge(baseConfig, {
plugins: [
new UglifyJsWebpackPlugin()
]
});
- 将
base.config.js
与dev.config.js
合并:
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config')
module.exports = webpackMerge(baseConfig, {
devServer: {
contentBase: './dist',
/* 是否实时进行监听 */
inline: true
}
})
-
合并完成删除
webpack.config.js
,此时再使用npm run dev
或者npm run build
就会出现找不到命令的问题。 -
解决合并文件只有删除
webpack.config.js
再使用npm run dev
或者npm run build
脚本命令出现的问题。修改package.json
。

网友评论