vuejs学习五:v-slot插槽、模块化开发、webpack、vue格式文件

v-slot插槽、模块化开发、webpack、vue格式文件

1 v-slot

目的是为了让组件的扩展性提高

1.1 简单使用

插槽就是复用性组件的预留空间。组件抽取共性保留不同

  • 使用slot标签定义一个插槽
  • slot中写的东西为该插槽默认值 <slot>插槽默认值</slot>
  • 使用组件时在中间添加的内容会替换插槽。
<body>
<div id="app">
  <cpn><button>按钮</button></cpn>
  <cpn><span>span</span></cpn>
  <cpn><i>我歪了</i></cpn>
</div>
</body>
<script src="../js/vue.js"></script>
<template id="cpn">
  <div>
    <h2>123</h2>
    <h3>下面那个是插槽</h3>
    <slot>插槽默认值</slot>
  </div>
</template>
<script>
  const app=new Vue({
    el:'#app',
    data:{
      message:'您好'
    },
    components:{
      cpn:{
        template:"#cpn"
      }
    }
  })
</script>

在这里插入图片描述

1.2 具名插槽

插槽定义时起名:name="插槽名"

插槽使用时给替换元素写上 slot=“插槽名” 找到对应的插槽:<button slot=“center”>我来替换中间插槽</button>

<body>
<div id="app">
  <cpn><p>只会替换无名字的</p><button slot="center">我来替换中间插槽</button></cpn>
</div>
</body>
<script src="../js/vue.js"></script>
<template id="cpn">
  <div>
    <slot><p>左边插槽</p></slot>
    <slot name="center">中间插槽</slot>
    <slot><p>右边插槽</p></slot>
  </div>
</template>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '您好'
    },
    components: {
      cpn: {
        template: "#cpn"
      }
    }
  })
</script>

1.3 作用域插槽

vue中的作用域可以理解成你在标签中用v-指令进行操作时找的是root级标签app中的属性和方法,还是组件中的属性和方法。

作用域插槽总结来说就是: 父组件替换插槽的标签,但是内容由子组件提供。

下面代码为一个普通的数组展示的代码,组件展示其内部的数组。

<body>
<div id="app">
  <cpn></cpn>
</div>
</body>
<template id="cpn">
  <div>
    <ul>
      <li v-for="item in pLanguages">{{item}}</li>
    </ul>
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "123"
    },
    components: {
      cpn: {
        template: "#cpn",
        data() {
          return {
            pLanguages: ["html", 'css', 'JavaScript']
          }
        }
      }
  }
  })
</script>

现在我们希望父组件(root)在调用该子组件时对v-for的每一步添加一些其他操作,这就需要我们的父组件可以访问到子组件内的data数据,这就要用到我们的作用域插槽

 <cpn>
    <template slot-scope="slot">
      <span v-for="item in slot.data">{{item}}--</span>
    </template>
  </cpn>
</div>
</body>
<template id="cpn">
  <div>
    <slot :data="pLanguages">
      <ul>
        <li v-for="item in pLanguages">{{item}}</li>
      </ul>
    </slot>
  </div>
</template>

2 模块化开发

我们先来看看为什么要使用模块化

2.1 为啥要用模块化

现在前端有俩人联合开发。

  //小明的aaa.js
  var name="小明"
  var flag=true
  function sum(num1,num2) {
    return num1+num2;
  }
 //小明又写了个bbb.js
  if (flag){
    console.log("flag为true");
  }
  //小红的hhh.js
  var flag=false
 

结果在页面上这样引用:

<script src="../js/aaa.js"></script>
  <script src="../js/hhh.js"></script>
  <script src="../js/bbb.js"></script>

小明的flag就会被小红覆盖。

于是我们想到用闭包匿名函数来封装这些变量,这样这些变量的作用域就变成匿名函数作用域了

  //小明的aaa.js
  (function f() {
    var name="小明"
    var flag=true
    function sum(num1,num2) {
      return num1+num2;
    }
  })();

这又带来了一个问题,这闭包里的属性和方法咋访问啊。

于是我们终于想到了模块化,匿名函数通过返回一个对象来储存需要的数据,搞一个唯一标识的全局变量指向这个对象。

  //小明的aaa.js
 var moduleA=(function f() {
    var returnObj={}
    var name="小明"
    var flag=true
    function sum(num1,num2) {
      return num1+num2;
    }
    returnObj.name=name;
    returnObj.flag=flag;
    returnObj.sum=sum;
    return returnObj;
  })();
//小明又写了个bbb.js
  if (moduleA.flag){
    console.log("flag为true");
  }

常见的模块化规范:CommonJS AMD CMD ES6的Modules

2.2 CommonJS简介(了解)

nodejs中有大量应用。

//导出 aaa.js
module.exports={
	flag:true,
    test(a,b){
        return a+b;
    }
}
//导入
var {flag,test}=require('aaa.js')
var aaa=require('aaa.js')
aaa.flag

2.3 es6 的模块化实现

//小明写的aaa.js
var flag=true;
function test(a,b) {
  return a+b;
}
//导出数据
export {
  flag,test
}
//小红写的bbb.js
var flag=false;
//小明的ccc.js 导入自己的aaa.js
import {flag,test} from "./aaa.js";
import getDefault from './aaa.js'

if (flag){
  console.log(1);
}
console.log(test(1, 2));

注意:在页面中引用是有说法的

  <script src="aaa.js" type="module"></script>
  <script src="bbb.js" type="module"></script>
  <script src="ccc.js" type="module"></script>

<script>
  console.log(flag);//flag is not defined
</script>

通过type=“module” 可以把引入的script做成一个单独的作用域,此时页面上已经无法直接访问其中的数据。

所有人都可以通过import来访问你export中暴露的数据。

导出有很多种写法

//导出方式2
export var num1=200;

//导出函数/类
export function sum(a,b) {
  return a+b;
}
export class Person{
  constructor(name,age){
    this.name=name;
    this.age=age;
  }
  run(){
    console.log(`${this.age}岁的${this.name}在跑`);
  }
}
//export default
//某些情况下一个模块的功能不希望给这个功能命名,就可以用export default,注意每个js只能这样导出一个数据
export default "default数据"
//可以导出函数
//export default function (argu) {
//  console.log(argu);
//}

export default的导入写法: getDefault 为使用者自定义的名字,写啥都行。

import getDefault from './aaa.js'

导入方法2

import * as aaa from './aaa.js';
console.log(aaa.flag);
aaa.default()

一般都是这么干,避免与当前js有冲突。意思就是把aaa.js导出的东西全部封装到aaa对象中

3 webpack

webpack是js的模块化打包工具。那么另一个前端打包工具grunt/gulp与webpack相比有何异同呢。

grunt/gulp的核心是task

  • 我们可以配置一些类的task ,定义器执行的事情(es6转化,ts转化,图片压缩等)

  • 之后让grunt/gulp 去执行这些task

  • 所以grunt/gulp也被称为前端自动化任务管理工具

  • 但是grunt/gulp对模块化是没有支撑的,webpack主要就是强调模块化的开发管理,grunt/gulp的功能webpack也有。

3.1 安装

webpack依赖于node环境,npm工具用来管理node的代码包(node packages manager)

  • 第一步装个node环境
  • 第二部 npm install webpack
  • 第三部 等完事测一下安装正确了吗 webpack -version

3.2 简单使用

这是我们项目目前的结构

在这里插入图片描述

我们的main.js 和mathUtils.js 如下

const {add, multi} = require('./mathUtils')
console.log(add(20, 30));
console.log(multi(20, 30));
function add(num1,num2) {
  return num1+num2;
}
function multi(num1,num2) {
  return num1*num2;
}
module.exports={
  add,multi
}

这里是使用commonJS的语法完成模块化js的,正常通过浏览器引入的话页面是无法解析的。

这时候webpack就登场了,在terminal使用指令

webpack ./src/main.js ./dist/bundle.js

通过webpack将main.js解析打包到dis文件夹下的bundle.js里,webpack在处理main.js时会看他是否有引用,有的话会连带着引用一起解析。下面是执行的结果。

在这里插入图片描述

之后我们只要在页面中引入这个bundle.js就可以实现所有的功能了。除了commonJs,AMD CMD es6module等模块化工具都可以使用webpack进行打包处理。

所以我们目前的开发应该是这样:

  • 在src中快乐的写模块化js
  • 让webpack帮我们进行模块化打包到bundle.js中
  • 引用bundle.js到页面

3.3 webpack的配置

首先创建一个js文件:webpack.config,webpack执行时会看这个webpack.config.js里有没有导出入口(entry)和出口(output)这俩参数。有的话就按照这俩参数执行

但是这个output.path他需要一个绝对路径,为了获取当前路径,我们要用一点node的知识。

我们先使用 npm install 来安装node的基本依赖,引用path模块,调用path.resolve(__dirname,"./dist")

它可以把当前路径(__dirname)和后面哪个拼接起来作为一个新的路径。

const path=require('path');

module.exports={
  entry:'./src/main.js',
  output:{
    //这里需要一个绝对路径,所以这里要动态获取路径
    path:path.resolve(__dirname,"./dist"),
    filename:'bundle.js'
  }
};

npm install之后,在package.json中,有一个scripts对象,这个就是用来控制命令的,你可以自定义命令名称和内容方便进行开发。而且这里的指令会优先执行本地安装的包,而直接webpack指令执行的是全局安装的包。

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "build": "webpack"
},

依赖可以分为,开发时依赖(像webpack就是专门用来打包的,运行时就没他事了)和运行时依赖,一般情况我们需要使用的包都是安装在本地的。在当前文件夹下安装webpack

npm install webpack@3.6.0 --save-dev //开发时依赖就这样安装--save-dev

安装完package.json中多一个,这就是开发时依赖的意思,与之相对的是dependencies(运行时依赖)

"devDependencies": {
    "webpack": "^3.6.0"
  }

调用自定义语句时使用:(build为指令名)

npm run build

3.4 webpack处理css

首先我们在main.js中引入css

require('./css/normal.css')

然后我们安装一下cssloader

npm install --save-dev css-loader

然后我们在webpack.config.js中添加如下配置(在官网找)

module: {
    rules: [
      {
        test: /\.css$/,
        use: ['css-loader']
      }
    ]
  }

这样我们就可以正确的解析css文件了,但是目前的css文件还无法添加到dom中去(页面上没效果)

我们还需要安装style-loader

npm install style-loader --save-dev

修改配置文件中的module

这个rules的原理是通过正则test匹配文件,然后使用下面的loader,使用loader时是从右向左读取的,所以要注意顺序(大部分官网都有)

module: {
    rules: [
      {
        //通过正则匹配下面的文件,然后使用下面的loader,使用loader时是从右向左读取的,所以要注意顺序
        test: /\.css$/,
        //css-loader只负责加载
        use: ['style-loader','css-loader']
      }
    ]
  }

然后 npm run build

3.5 less文件处理

先写个less

@fontSize:50px;
@fontColor:orange;
body{
  font-size: @fontSize;
  color:  @fontColor;
}

还是main.js 先依赖

require('./css/font.less')

下载loader 后面哪个less是用来把less转css的工具

npm install --save-dev less-loader less

添加配置

  {
        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
        }]
      }

然后 npm run build

3.6 图片处理

body{
  background: url("../img/mvvm.jpg");
}

webpack对图片会处理为模块依赖,所以又需要loader

使用url-loader

安装:npm install --save-dev url-loader

配置:

 {
        test: /\.(png|jpg|gif|jpeg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192
            }
          }
        ]
      }

build

//加载图片小于这个limit时会编译成Base64字符串
//想加载大的要再引入一个file-loader

安装完file-loader发现还是不行,不过打包完dist多了一个图
在这里插入图片描述
在这里插入图片描述

其实页面上已经找了这个图,只不过少了个dist路径

 output: {
    //这里需要一个绝对路径,所以这里要动态获取路径
    path: path.resolve(__dirname, "./dist"),
    filename: 'bundle.js',
    publicPath:'dist/'
  }

我们再配置文件的output中添加一个publicPath属性,该属性会让所有的url引用前都添加一个’dist/'字符

目前的图片名是32位hash,如何控制图片名称和路径呢?

通过options的配置属性name来控制,注意写的位置,写在rules数组的图片loader相关对象中

{
        test: /\.(png|jpg|gif|jpeg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10,
              //img路径下,[name]会取出原来图片的名字,[hash:8]为8位随机不重复hash值,[ext]为当前的扩展名
              name:'img/[name].[hash:8].[ext]'
            },

          }
        ]
      }

在这里插入图片描述

3.7 转es6

webpack默认是es6的,要转es5 要安装一个babel的loader

npm install babel-loader babel-core babel-preset-env

配置:

    {
      test: /\.js$/,
          //排除下面这个文件夹
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }

我们正常开发时会借助脚手架不会像上面那样一个一个配的

4 webpack与vue

4.1 webpack中用vue

先安装 npm install vue --save vue是运行时依赖

main.js中导入vue

import Vue from 'vue'
const app=new Vue({
  el:'#app',
  data:{
    message:"123"
  }
})

index 写id为app的div。这样会出错,因为vue这里有两类版本:

  • runtime-only 代码中不可以有任何的template(挂载给app也会被认为是template),他不会编译

  • rentime-compiler: 可以有template 因为有compiler可以用于编译template

这时我们是在使用runtime-only版本

解决方法:在webpack的配置文件中添加属性

resolve:{
    //别名,这样他会跑到nodemodule的vue里面去找这个js,默认找那个是runtime-only的vue.js
    alias:{
      'vue$':'vue/dist/vue.esm.js'
    }
  }

这样使用vue我们要在页面上改页面,改完了还要去js里改很麻烦。所以我们可以这样做:

new Vue({
  el:'#app',
  template:`
  <div>
    <h2>{{message}}</h2>
    <button @click="btnClick">按钮</button>
  </div>
  `,
  data:{
    message:"123"
  },
  methods:{
    btnClick(){
      console.log(1);
    }
  }
});

template 属性会替换你挂载的元素(#app)

这里我们遇到了一个问题,html页面报警告:找不到#app元素,原因是我们的bundle.js文件要引在我们dom树后面,引在前面还没加载到页面就执行了vue的代码。

4.2 .vue

终于要介绍.vue了。我们觉得上面那个代码很冗长,于是把他的template data methods都抽取出来捏成了一个组件,而new Vue只需要挂载元素和设置components组件即可。然后我们又把抽出来的组件整合到了一下,就产生了.vue文件

<template>
  <div>
    <h2 class="title" >{{message}}</h2>
    <button @click="btnClick">按钮</button>
  </div>
</template>

<script>
  export default {
    name: "App",
    data() {
      return {message: "123"}
    },
    methods: {
      btnClick() {
        console.log(1);
      }
    }
  }
</script>

<style scoped>
.title{
  background: green;
}
</style>

当然.vue文件 webpack还是无法解析的

npm install --save-dev vue-template-compiler vue-loader

vue-loader 14以上配置完还得配置一个插件,我们这里先改package改成13版本。

配置文件rules

{
        test: /\.vue$/,
        use: ['vue-loader']
      }

目前的main.js

new Vue({
  el:'#app',
  template:"<App/>",
  components:{
    App
  }
})

4.3 plugin

  • 版权所有插件

    还是在webpack.config中

    const webpack=require("webpack")
    module.exports = {
    plugins:[
        new webpack.BannerPlugin("最终版权归咕咕咕所有")
      ]}

    在bundle.js里可以看到这句话

  • html打包插件

    我们的index.html肯定也要放到dist里,用到HtmlWebpackplugin

    下载引入

    npm install html-webpack-plugin --save-dev
    //config
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    plugins:[
    new HtmlWebpackPlugin({
          template: 'index.html' //他会将src下的index.html添加到dist中,并且自动引入bundle.js
        })
        ]
  • js压缩插件(丑化) uglfiyjs-webpack-plugin

    丑化就是把空格注释删了,名称全用简写

4.4 搭建本地服务器

npm install webpack-dev-server@2.9.3  --save-dev

配置devServer

module.exports = {
      devServer:{
    //用于服务 dist文件夹
    contentBase:'./dist',
    inline:true, //页面实时刷新
    port:8080 //端口 默认8080
  }
}

配置package.json的scripts

    "dev": "webpack-dev-server --open" //--open自动打开

不写的话,执行webpack-dev-server会跑到全局里面找webpack-dev-server,但是全局并没有安装,所以必须添加这个指令。这样我们开发时在src中修改内容,不需要webpack打包就可以通过devServer来访问,等我们觉得开发好了,再通过webpack打包发布。

4.5 webpack 配置分离

根据开发依赖和发布时依赖,对配置进行分离.分别创建开发时依赖和生产依赖,再创建一个俩都用的依赖。开发时用base+dev 生产用base+prod。

在这里插入图片描述

npm install webpack-merge --save -dev

暴露时,调用webpackMerge的方法,他会把两个config整合
dev.config.js

//开发时配置
const webpackMerge=require('webpack-merge')
const baseConfig=require("./base.config.js")
//暴露时,调用webpackMerge的方法,他会把两个config整合

module.exports=webpackMerge(baseConfig,{
  devServer:{//开发服务器插件
    //用于服务 dist文件夹
    contentBase:'./dist',
    inline:true, //页面实时刷新
    port:8080 //端口 默认8080
  }
})

prod.config.js

//生产
const uglifyjsWebpackPlugin=require("uglifyjs-webpack-plugin");
const webpackMerge=require('webpack-merge')
const baseConfig=require('./base.config.js')
module.exports = webpackMerge(baseConfig,{
  plugins: [//js丑化插件
    new uglifyjsWebpackPlugin()
  ]
});

剩下的放到base.config中

然后调整package.json中的脚本部分

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config ./config/prod.config.js",
    "dev": "webpack-dev-server --open --config ./config/dev.config.js"
  },

通过–config告诉他执行指令时去哪找配置文件
开发时用 npm run dev指令,发布时用 npm run build指令

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值