>>分享Web前端开发技术,并对孙卫琴的《精通Vue.js:Web前端开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 16435 个阅读者 刷新本主题
 * 贴子主题:  Vue用法详解 回复文章 点赞(0)  收藏  
作者:sunshine    发表时间:2021-02-04 00:49:16     消息  查看  搜索  好友  邮件  复制  引用

    

相关概念

混合开发和前后端分离

  •   混合开发(服务器端渲染)
  •   前后端分离

    后端提供接口,前端开发界面效果(专注于用户的交互)

库和框架

  •   库

         库提供大量API,需要自己调用这些API简化开发。
  •   框架

         框架提供了一些基础服务,一般不需要自己调用,会自动完成一些基本功能。

什么是Vue

什么是Vue

  •   一款非常优秀的前端 JavaScript 框架,由尤雨溪创建开发
  •   可以轻松构建单页 (SPA) 应用程序
  •   通过 指令 扩展了 HTML,通过 表达式 绑定数据到 HTML
  •   最大程度上解放了 DOM 操作
  •   它能让你更加的享受编程的乐趣
  •   数据驱动,开源

         官网

Vue的特点

  • 简单易用
  • 灵活渐进式
  • 轻量高效
  • 虚拟 DOM
  • MVVM
  • 组件化

Vue初体验

安装Vue

下载Vue

  •   Vue.js 不支持 IE8 及其以下版本
  •   最新稳定版本:2.5.16
  •   直接下载
  •   CDN    

    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>

  •   使用npm下载(默认安装最新稳定版)    

    npm install vue

Hello World

通过数据绑定的方式,在界面上展示Hello World    

<div id="app">
    <h1>{{ msg }}</h1>
</div>
<script src="vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'Hello World'
        }
    });
</script>

Vue实例

创建Vue实例

每一个Vue应用都是通过Vue构造函数创建一个Vue的实例开始    

var vm = new Vue({
    // Vue的选项
});

  • Vue的选项
    •   el选项:指定Vue作用的范围
    • data 选项:data提供数据对象,绑定的数据

模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML ,所以能被遵循规范的浏览器和 HTML 解析器解析。

插值表达式

数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:    

<h1>
    {{ msg }}
</h1>

JavaScript表达式

对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。    

{{ number + 1 }}

{{ age > 18 ? '年满18岁' : '未满18岁' }}

{{ message.split('').reverse().join('') }}

<h1>
    {{ msg }}
</h1>

   注意:差值表达式中不能写语句。例如:var a = 10;

指令

指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是 单个 JavaScript 表达式(v-for是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。参考文档

v-html/v-text

  • v-text
    • v-text和差值表达式的区别
      • v-text 标签的指令更新整个标签中的内容
      • 差值表达式,可以更新标签中局部的内容
  • v-html
    • 可以渲染内容中的HTML标签
    • 尽量避免使用,否则会带来危险(XSS攻击 跨站脚本攻击)

v-bind

可以绑定标签上的任何属性。
  •   动态绑定图片的路径    

    <img v-bind:src="src" />
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                src: '1.jpg'
            }
        });
    </script>

  •   绑定a标签上的id    

    <a v-bind:href="'del.php?id=' + id">删除</a>
    <script>
      var vm = new Vue({
            el: '#app',
            data: {
                id: 11
            }
        });
    </script>

  •   绑定class

         对象语法和数组语法
    •   对象语法

           如果isActive为true,则返回的结果为

      <div class="active"></div>

      <div v-bind:class="{active: isActive}">
          hei
      </div>
      <script>
          var vm = new Vue({
              el: '#app',
              data: {
                  isActive: true  
              }
          });
      </script>

    •   数组语法

           渲染的结果

      <div class="active text-danger"></div>

      <div v-bind:class="[url=]">
          hei
      </div>
      <script>
          var vm = new Vue({
              el: '#app',
              data: {
                  activeClass: 'active',
                  dangerClass: 'text-danger'
              }
          });
      </script>

  •   绑定style

         对象语法和数组语法
    •   对象语法

           渲染的结果<div style="color: red; font-size: 18px;"></div>    

      <div v-bind:style="{color: redColor, fontSize: font18 + 'px'}">
          hei
      </div>
      <script>
          var vm = new Vue({
              el: '#app',
              data: {
                  redColor: 'red',
                  font18: 18
              }
          });
      </script>

    •   数组语法    

      <div v-bind:style="[color, fontSize]">abc</div>
      <script>
          var vm = new Vue({
              el: '#app',
              data: {
                  color: {
                      color: 'red'
                  },
                  fontSize: {
                      'font-size': '18px'
                  }
              }
          });
      </script>

  •   简化语法    

    <div v-bind:class="{active: isActive}">
    </div>
    <!-- 可以简化为,简化语法更常用 -->
    <div :class="{active: isActive}">
    </div>

v-model

表单元素的绑定
  •   双向数据绑定
    • 数据发生变化可以更新到界面
    • 通过界面可以更改数据
  •   绑定文本框

         当文本框的值发生边框后,div中的内容也会发生变化    

    <input type="text" v-model="name">
    <div>{{ name }}</div>
    <script>
        var vm = new Vue({
           el: '#app',
            data: {
                name: ''
            }
        });
    </script>

  •   绑定多行文本框    

    <textarea v-model="name"></textarea>
    <div>{{ name }}</div>

       注意:多行文本框中不能使用{{name}}的方式绑定
  •   绑定复选框
    • 绑定一个复选框
    <input type="checkbox" v-model="checked">
    <div>{{ checked }}</div>

    •   绑定多个复选框

           此种方式需要input标签 提供value属性
    吃饭:<input type="checkbox" value="eat" v-model="checklist"><br>
    睡觉:<input type="checkbox" value="sleep" v-model="checklist"><br>
    打豆豆:<input type="checkbox" value="ddd" v-model="checklist"><br>
    {{ checklist }}
    <script>
        var vm = new Vue({
           el: '#app',
            data: {
                checklist: []
            }
        });
    </script>

  •   绑定单选框    

    男<input type="radio" name="sex" value="男" v-model="sex">
    女<input type="radio" name="sex" value="女" v-model="sex">
    {{sex}}
    <script>
        var vm = new Vue({
           el: '#app',
            data: {
                sex: ''
            }
        });
    </script>

  •   绑定下拉框    

    <div id="example-5">
      <select v-model="selected">
        <option disabled value="">请选择</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
      </select>
      <span>Selected: {{ selected }}</span>
    </div>

v-on

  •   绑定事件
  •   事件修饰符:
    • .prevent

    • .once

  •   简化语法    

    <a href="#" @click.prevent="handleDelete">删除<a>

v-show

v-if

v-for

v-cloak

v-once

  • 一次性绑定

Vue的选项对象

当创建一个 Vue 实例时,你可以传入一个 选项对象。你可以在 API 文档 中浏览完整的选项列表。
  • el选项
      参考文档:https://cn.vuejs.org/v2/api/#el
    提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。

         注意:
    • 不能作用到<html>或者<body>上
    • 也可以通过实例.$mount()手动挂载
  • data选项
      参考文档:https://cn.vuejs.org/v2/api/#data
    • Vue 实例的数据对象,能够响应式数据变化( 双向绑定)
    • 可以通过vm.$data访问原始数据对象
    • Vue 实例也代理了 data 对象上所有的属性,因此访问 vm.a等价于访问 vm.$data.a
    • 视图中绑定的数据必须显式的初始化到 data 中
  • methods选项
      参考文档:https://cn.vuejs.org/v2/api/#methods
    methods 将被混入到 Vue 实例中。可以直接通过vm 实例访问这些方法,或者在指令表达式中使用。方法中的 this自动绑定为 Vue 实例。

         注意: 不应该使用箭头函数来定义 method 函数 (例如  plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以this将不会按照期望指向 Vue 实例,this.a将是 undefined。    

    var vm = new Vue({
      data: { a: 1 },
      methods: {
        plus: function () {
          this.a++
        }
      }
    })
    vm.plus()
    vm.a // 2

案例:表格操作

  • 展示列表数据
  • 删除数据
  • 添加数据
总结:
  • Vue 最大程度上减少了页面上的 DOM 操作
  • 让开发人员更专注于业务操作
  • 通过简洁的指令结合页面结构与逻辑数据
  • 代码结构更合理
  • 维护成本更低
  • 数据驱动
  • VueJS 解放了传统 JavaScript 中频繁的 DOM 操作

DevTools

https://github.com/vuejs/vue-devtools

MVVM

            点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

MVVMPattern.png

其它知识点

过滤器

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方: 双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。

     需求:对表格案例中的日期进行格式化。    

<td>{{ item.date | fmrTime('YYYY-MM-DD HH:mm:ss') }}</td>
<script>
Vue.filter('fmrTime', function (time, formatStr) {
    // 使用moment.js对日期进行格式化
    return moment(time).format(formatStr);
});
</script>

计算属性

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。
  •   计算属性当依赖的data中的数据发生变化的时候执行
  •    计算属性是基于它们的依赖进行缓存的,计算属性只有在它的相关依赖发生改变时才会重新求值。
      参考文档
通过获取时间,演示计算属性和methods中方法的区别(缓存数据的差异)。

     计算属性和方法的区别
  1. 方法每次调用都会执行
  2. 计算属性只有当依赖的数据方法变化才会执行
需求:表格案例中实现搜索功能    

<tr v-for="(item, index) in newList" :key="index">
....
<tr v-if="newList.length === 0">
<script>
    var vm = new Vue({
        el: ....
        computed: {
            newList() {
              return this.list.filter((item) => {
                return item.name.startsWith(this.searchKey);
              });
            }
          }
    })
</script>

ref

在Vue.js中操作DOM。

     需求:表格案例中让文本框默认获得焦。
  1. 给要获取焦点的元素增加ref属性
  2. 在mounted中通过$refs获取DOM元素
<input type="text" ref="username" v-model="name">

<script>
    var vm = new Vue({
       el: '#app',
       // mounted当页面加载完毕执行
       mounted: function () {
           this.$refs.username.focus();
       },
       data.....,
    });
</script>

   注意:Vue.js中不推荐直接操作DOM,除非必须否则不建议这么使用。

自定义指令

除了核心功能默认的指令,例如:v-model和v-show,Vue 也允许注册自定义指令。

     需求:表格案例中让文本框默认获得焦。 给文本框增加自定义指令 v-focus    

<input type="text" v-focus v-model="name">
<script>
// 全局自定义指令
Vue.directive('focus', {
    inserted: function (el) {
        el.focus();
    }
});
</script>

发送网络请求

在Vue.js中发送网络请求本质还是ajax,我们可以使用插件方便操作。
  •   vue-resource

         Vuejs的插件,已经不维护,作者不推荐使用
  •    axios

         可以在任何地方使用,推荐

axios

既可以在浏览器端又可以在node.js中使用的发送http请求的库,支持Promise,默认不支持jsonp。官网
  •   发送get请求    

    axios.get('http://localhost:3000/brands')
          .then(res => {
            console.log(res.data);
          })
          .catch(err => {
            console.dir(err)
          });

  •   发送delete请求    

    axios.delete('http://localhost:3000/brands/109')
          .then(res => {
            console.log(res.data);
          })
          .catch(err => {
            console.dir(err)
          });

  •   发送post请求    

    axios.post('http://localhost:3000/brands', {name: '小米', date: new Date()})
          .then(res => {
            console.log(res);
          })
          .catch(err => {
            console.dir(err)
          });

  •   jsonp

         https://github.com/axios/axios/blob/master/COOKBOOK.md    

    jsonp('http://localhost:3000/brands', (err, data) => {
          if (err) {
            console.dir(err.msg);
          } else {
            console.dir(data);
          }
        });

表格案例

  •   数据列表
  •   删除数据
  •   添加数据
  •   查询数据
    •   侦听器

           监听data对象的searchKey属性的变化,执行相应的操作
    watch: {
        searchKey: function (newValue, oldValue) {
            // 发送请求获取列表数据
            axios.get('http://localhost:3000/brands?name_like=' + newValue)
                .then(res => {
                this.list = res.data;
            })
                .catch(err => {
                console.log(err);
            });
        }

过渡和动画

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

在 CSS 过渡和动画中自动应用 class

Vue 提供了transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡    

// v要替换成transition组件的name属性值
v-enter:定义进入过渡的开始状态。
v-enter-active:定义进入过渡生效时的状态。
v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。
v-leave: 定义离开过渡的开始状态。
v-leave-active:定义离开过渡生效时的状态。
v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。

   示例:    

<style>
    .box {
        position: absolute;
        left: 0;
        top: 50px;
        width: 100px;
        height: 100px;
        background-color: red;
    }
    .slide-enter, .slide-leave-to {
        left: 200px;
        opacity: 0;
    }
    .slide-enter-active, .slide-leave-active {
        transition: all 2s;
    }
    .slide-enter-to, .slide-leave {
        left: 0px;
        opacity: 1;
    }
</style>
<button @click="isShow = !isShow">显示/隐藏</button>

<transition name="slide">
    <div v-show="isShow" class="box"></div>
</transition>
<script>
    var vm = new Vue({
      el: '#app',
      data: {
        isShow: true
      }
    });
</script>

自定义过渡动画的类名

可以通过transition组件自定义过渡动画的类名,可以方便结合第三方的动画库使用,比如:animate.css    

// transition组件的属性
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)

   示例:    

<button @click="isShow = !isShow">toggle</button>
<transition
            enter-active-class="animated fadeIn"
            leave-active-class="animated fadeOut">
    <div v-show="isShow">hello</div>
</transition>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            isShow: true
        }
    });
</script>

组件

什么是组件

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:

                点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

components.png

组件和模块

  • 模块:侧重于功能或者数据的封装
  • 组件:包含了 template、style 和 script,而它的 script 可以由各种模块组成
            点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

b25efd3e8af188b5ab36ccb66baddd71_hd.jpg

Vue中的组件开发

组件是可复用的 Vue 实例,且带有一个名字,比如 <my-breadcrumb>。把这个组件作为自定义元素来使用。组件的好处是写一次可以进行任意次数的复用。

     组件参考文档

全局组件

Vue.component('my-breadcrumb', {
      template: `<div>
          <span>{{ level1 }}</span>
          <span>/</span>
          <span @click="t">{{ level2 }}</span>
        <div>`,
      data() {
        return {
          level1: '用户管理1',
          level2: '用户列表1'
        };
      },
      methods: {
        t() {
          alert('hello');
        }
      }
    });

   注意:
  1. 组件的模板中必须有且只有一个根标签
  2. 组件是一个特殊的Vue实例
  3. 组件中的data是一个方法,目的是让每一个组件维护一个自己的数据
  4. 组件有自己的作用域

私有组件

// 私有组件
var ComponentA = {
    template: '<div>{{ msg }}</div>',
    data() {
        return {
            msg: 'hello'
        };
    }
};
var vm = new Vue({
    el: '#app',
    components: {
        'component-a': ComponentA
    }
});

通过Props给子组件传值

  1.   子组件可以通过props 选项接收一个一些值,通过props传递的值变成了改组件的一个属性。    

    var ComponentA = {
        template: '<div>{{ title }}</div>',
        props: ['title'],
    };

  2.   当然子组件具有props选项后,数据可以通过标签的自定义属性传递给子组件    

    <component-a :title="msg"></component-a>

  3.   在vue的实例中提供该属性值    

    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'hello heima',
        },
        components: {
            'component-a': ComponentA
        }
    });

      ?

Vue实例的生命周期

  •   什么生命周期

         定义:生命周期是指vue实例或者组件从诞生到消亡经历的每一个阶段,在这些阶段的前后可以设置一些函数当做事件来调用。
  •   参考

         生命周期
  •   生命周期中的钩子函数
//创造vue实例之后运行此函数,vm中的data/methods中的成员不可用
beforeCreate: function () {
   console.log("beforeCreate")
}

//创造vue实例之后运行此函数,vm中的data/methods属性可用
created: function () {
  console.log("created")
}

//当vue实例的el节点或组件挂载到页面以前运行次函数
beforeMount: function () {
    console.log("beforeMount")
}

//当vue实例的el节点或组件挂载到页面以后运行次函数
mounted: function () {
    console.log("mounted")
}

//当vue实例数据发生改变前触发此函数
beforeUpdate: function () {
    console.log("beforeUpdate")
}

//当vue实例数据发生改变后触发此函数
updated: function () {
    console.log("updated")
}

前端路由

单页应用

  •   什么是单页应用

         单页应用(single page web application, SPA),是在一个页面完成所有的业务功能,浏览器一开始会加载必需的HTML、CSS和JavaScript,之后所有的操作都在这张页面完成,这一切都由JavaScript来控制。
  •   单页应用优缺点
    • 优点
      • 操作体验流畅
      • 完全的前端组件化
    • 缺点
      • 首次加载大量资源(可以只加载所需部分)
      • 对搜索引擎不友好
      • 开发难度相对较高
  •   单页应用的原理
    •   Hash路由
      •   利用URL上的hash,当hash改变不会引起页面刷新,所以可以利用 hash 值来做单页面应用的路由,

             并且当 url 的 hash 发生变化的时候,可以触发相应 hashchange 回调函数。
      •   模拟实现
      var app = document.getElementById('app');
      window.onhashchange = function () {
          var hash = location.hash.replace('#', '');
          switch (hash.toLowerCase()) {
              case '/':
                  app.innerHTML = '首页内容';
                  break;
              case '/users':
                  app.innerHTML = '用户管理内容';
                  break;
                  ……
          }
      };

    •   History路由
      • History 路由是基于 HTML5 规范,在 HTML5 规范中提供了 history.pushState || history.replaceState 来进行路由控制。

vue-router

快速体验

  1.   导入vue和vue-router
  2.   设置HTML中的内容    

    <!-- router-link 最终会被渲染成a标签,to指定路由的跳转地址 -->
    <router-link to="/users">用户管理</router-link>

    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>

  3.   创建组件    

    // 创建组件
    // 组件可以放到单独的js文件中
    var Home = {
        template: '<div>这是Home内容</div>'
    };
    var Users = {
        template: '<div>这是用户管理内容</div>'
    };

  4.   配置路由规则    

    // 配置路由规则
    var router = new VueRouter({
        routes: [
            { name: 'home', path: '/', component: Home },
            { name: 'users', path: '/users', component: Users }
        ]
    });

  5.   设置vue的路由选项    

    var vm = new Vue({
        el: '#app',
        router
    });

动态路由匹配

假设有一个用户列表,想要删除某一个用户,需要获取用户的id传入组件内,如何实现呢?

     此时可以通过路由传参来实现,具体步骤如下:
  1.   路由规则中增加参数,在path最后增加 :id    

    { name: 'users', path: '/users/:id', component: Users },

  2.   通过 <router-link> 传参,在路径上传入具体的值    

    <router-link to="/users/120">用户管理</router-link>

  3.   在组件内部可以使用, this.$route 获取当前路由对象    

    var Users = {
        template: '<div>这是用户管理内容 {{ $route.params.id }}</div>',
        mounted() {
            console.log(this.$route.params.id);
        }
    };

webpack

webpack 是一个模块打包器。webpack 的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用。

     参考网站: 中文参考网站    官网

安装webpack

最新webpack版本4.x
  1. 本地安装webpack
  2. 安装webpack的命令行工具  webpack-cli
$ npm install webpack webpack-cli --save-dev

快速实践

参考官网
  • 项目结构,默认的目录和文件名称不可修改
   webpack-demo
  |- package.json
+ |- /dist
+ |- index.html
  |- /src
    |- index.js

  • 入口js文件,默认名称index.js
math.js    

export default {
  add(a, b) {
    return a + b;
  },
  sub(a, b) {
    return a - b;
  }
};

  index.js    

import Math from './math';

var x = 5;
var y = 6;

console.log(Math.add(5, 6));
console.log(Math.sub(5, 6));

  • 运行
$ npm webpack

配置文件 webpack.config.js

webpack4.x 以前,必须要有配置文件。在 webpack 4.x 以后,可以无须任何配置使用(),然而大多数项目会需要很复杂的设置,这就是为什么 webpack 仍然要支持。
  •   使用步骤
    • 项目根目录下,手动新建webpack.config.js
    const path = require('path');
    module.exports = {
      // 配置入口文件
      entry: './src/index.js',
      // 配置打包的文件和路径
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
      }
    };

    • 运行命令
    $ npm webpack --config webpack.config.js

       注意:打包的文件名改变后,要修改index.html的script标签引入的文件名

         <script src="bundle.js"></script>
  •   NPM脚本

         输入上面的命令太繁琐,可以直接在终端运行 webpack,会默认加载webpack.config.js配置文件。
    • 在package.json中新增
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
      },

    • 终端输入
    $ npm run build

webpack常用的Loader

webpack 最出色的功能之一就是,除了 JavaScript,还可以通过 loader 引入任何其他类型的文件。webpack 可以把所有文件作为模块, 动态打包(dynamically bundle)所有依赖项。

     参考文档

打包CSS

  •   安装和配置 style-loadercss-loader
    • 安装
    $ npm install --save-dev style-loader css-loader

    • 配置,在webpack.config.js中
       const path = require('path');
      module.exports = {
        entry: './src/index.js',
        output: {
          filename: 'bundle.js',
          path: path.resolve(__dirname, 'dist')
        },
    +   module: {
    +     rules: [
    +       {
    +         test: /\.css$/,
    +         use: [
    +           'style-loader',
    +           'css-loader'
    +         ]
    +       }
    +     ]
    +   }
      };

  •   在入口index.js中,导入css模块    

    import './css/index.css';

  •   运行webpack命令    

    $ npm run build

打包less

  •   安装和配置    

    $ npm install less-loader less --save-dev

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

  •   less    

    @color: yellow;
    body {
        background-color: @color;
    }

打包sass

  •   安装和配置    

    $ npm install sass-loader node-sass --save-dev

    {
        test: /\.scss$/,
        use: [
           'style-loader',
           'css-loader',
           'sass-loader'
        ]
    }

  •   scss    

    $color: red;
    body {
        background-color: $color;
    }

加载图片

使用 file-loader 可以加载图片和字体
  •   安装和配置    

    $ npm install --save-dev file-loader

    {
      test: /\.(png|svg|jpg|gif)$/,
      use: [
          'file-loader'
      ]
    }

加载字体

  •   配置    

    {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
           'file-loader'
        ]
    }

webpack常用插件

除了通过loader去处理不同的资源文件以外,webpack还支持插件机制,通过插件可以完成更多的事情。

HtmlWebpackPlugin

自动生成index.html,并引入资源文件,还可以通过配置压缩HTML。
  •   安装    

    npm install --save-dev html-webpack-plugin

  •   配置    

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    ......
    plugins: [
        new HtmlWebpackPlugin({
            // 文档的标题
            title: 'Output Management',
            // 生成的文档文件名
            filename: 'index.html',
            // 模板文件
            template: 'index.html',
            minify: {
              collapseWhitespace: true
            }
        })
    ]
    ......

CleanWebpackPlugin

清空dist目录。
  •   安装    

    npm install clean-webpack-plugin --save-dev

  •   配置    

    const CleanWebpackPlugin = require('clean-webpack-plugin');

    ……
    new CleanWebpackPlugin(['dist']),
    ……

使用source map

参考文档

     在webpack.config.js中添加    

devtool: 'inline-source-map',

使用 webpack-dev-server

webpack-dev-server[为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。让我们设置以下:    

$ npm install --save-dev webpack-dev-server

   webpack.config.js    

devServer: {
    contentBase: './dist'
},

   package.json    

"start": "webpack-dev-server --open"

启用HMR

模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。

     webpack.config.js    

const webpack = require('webpack');

.......
devServer: {
    contentBase: './dist',
    hot: true
},
.......

.......
     new webpack.NamedModulesPlugin(),
     new webpack.HotModuleReplacementPlugin()
.......

综合案例

单文件组件

可以通过 .vue 文件封装组件,参考文档
  •   处理 .vue 文件 — 使用 vue-loader

         vue-loader使用比较特殊,如下    

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

    // 配置loader
    {
        test: /\.vue$/,
        loader: 'vue-loader'
    }

案例演示

            点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

image-20180526145007221.png

搭建项目结构

  •   新建项目
    • 初始化package.json
    # 注意项目名称不能有中文
    $ npm init -y

    • 拷贝 webpack.config.js 到根目录
    • 拷贝依赖
    "devDependencies": {
        "clean-webpack-plugin": "^0.1.19",
        "css-loader": "^0.28.11",
        "file-loader": "^1.1.11",
        "html-minifier": "^3.5.16",
        "html-webpack-plugin": "^3.2.0",
        "less": "^3.0.4",
        "less-loader": "^4.1.0",
        "node-sass": "^4.9.0",
        "sass-loader": "^7.0.1",
        "style-loader": "^0.21.0",
        "url-loader": "^1.0.1",
        "vue-loader": "^15.2.0",
        "vue-template-compiler": "^2.5.16",
        "webpack": "^4.8.3",
        "webpack-cli": "^2.1.4",
        "webpack-dev-server": "^3.1.4"
      },
      "dependencies": {
        "vue": "^2.5.16"
      }

    • 安装依赖
    $ npm install

    • 下载bootstrap3
    $ npm install bootstrap@3.3.7 --save

  •   项目结构

         [图片上传失败...(image-de211b-1527597271494)]

配置根组件

  •   从模板中复制自定义样式 index.css 到assets/css目录
  •   入口文件 src/index.js    

    import Vue from 'vue';
    import App from './App.vue';

    // 导入bootstrap样式
    import 'bootstrap/dist/css/bootstrap.css';
    // 导入自定义样式
    import './assets/css/index.css';

    const vm = new Vue({
      el: '#app',
      render: c => c(App)
    });

  •   根组件 src/App.vue

         复制模板中index.html的内容到App.vue中
  •   运行测试    

    $ npm start

提取子组件

  •   提取头部组件 components/header.vue
  •   提取侧边栏组件 components/sidebar.vue
  •   提取英雄列表组件 views/hero-list.vue
  •   根组件 src/App.vue 中加载组件    

    import Header from './components/header.vue';
    import Sidebar from './components/sidebar.vue';
    import Heroes from './views/heroes.vue';
    export default {
      components: {
        Header,
        Sidebar,
        Heroes
      }
    };

    <div>
        <Header></Header>
        <div class="container-fluid">
            <div class="row">
                <Sidebar></Sidebar>
                <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                    <h2 class="sub-header">Hero List</h2>
                    <a class="btn btn-success" href="add.html">Add</a>
                    <div class="table-responsive">
                        <Heroes></Heroes>
                    </div>
                </div>
            </div>
        </div>
    </div>

使用 Vue-Router 实现页面导航管理

  Vue-Router 能帮我们实现点击某个导航链接的时候动态的展示一个组件
  •   安装路由模块    

    $ npm install vue-router --save

  •   注册路由插件

         在index.js中,加载路由插件    

    import VueRouter from 'vue-router';
    // 注册路由插件
    Vue.use(VueRouter);

  •   加载组件,配置路由规则

         index.js中    

    // 加载组件
    import Heroes from './views/heroes/heroes.vue';
    import Weapons from './views/weapons.vue';
    import Equips from './views/equips.vue';
    // 配置路由规则
    const router = new VueRouter({
      routes: [
        // 设置根路径跳转到英雄管理界面
        {'name': 'home', path: '/', redirect: {name: 'heroes'}},
        {'name': 'heroes', path: '/heroes', component: Heroes},
        {'name': 'weapons', path: '/weapons', component: Weapons},
        {'name': 'equips', path: '/equips', component: Equips}
      ]
    });

    new Vue({
      el: '#app',
      render: c => c(App),
      // 设置路由
      router
    });

  •   在 src/App.vue组件中留路由出口(告诉路由往哪里渲染 path 匹配到的组件)    

    <Sidebar></Sidebar>
    <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
        <router-view></router-view>
    </div>

  •   在侧边栏 src/components/sidebar.vue 组件中 增加两个导航链接

         将激活-class-应用在外层元素    

    <ul class="nav nav-sidebar">
        <router-link to="/heroes" tag="li" active-class="active">
            <a>英雄列表</a>
        </router-link>
        <router-link to="/weapons" tag="li" active-class="active">
            <a>武器列表</a>
        </router-link>
        <router-link to="/equips" tag="li" active-class="active">
            <a>装备列表</a>
        </router-link>
    </ul>

JSON Server

可以快速开启 REST API 测试服务器的工具命令行工具。官网

安装

$ npm install json-server -g

使用

$ json-server --watch db.json

接口地址

  • 获取英雄列表
  •   根据英雄id获取一个英雄
  •   添加英雄
    {
      name: '英雄名称',
      gender: '英雄性别'
    }

  •   删除英雄
  •   编辑英雄
    •   请求路径:

      http://localhost:3000/heros/:id
      • :id需要给定一个英雄的 id
    •   请求方法:PATCH
    •   请求体:    

      {
        name: '英雄名称',
        gender: '英雄性别'
      }

实现项目功能

安装 axios 到项目中    

  $ npm install axios --save

英雄列表

JS    

import axios from 'axios';
export default {
  data() {
    return {
      heroes: []
    };
  },
  mounted() {
    this.loadData();
  },
  methods: {
    async loadData() {
      const res = await axios.get('http://localhost:3000/heros');
      this.heroes = res.data;
    }
  }
};

   HTML    

<tr v-for="(item, index) in heroes" :key="item.id">
    <td>{{ index + 1 }}</td>
    <td>{{ item.name }}</td>
    <td>{{ item.gender }}</td>
    <td>
        <!-- <router-link :to="'/edit/' + item.id"></router-link> -->
        <a href="edit.html">edit</a>
          
        <a href="javascript:window.confirm('Are you sure?')">delete</a>
    </td>
</tr>

删除英雄

HTML    

<!-- prevent 修饰符,阻止后续内容的执行 -->
<a href="#" @click.prevent="handleClick(item.id)">delete</a>

   JS    

async handleClick(id) {
    const isConfirmed = confirm('确认要删除该英雄?');
    if (!isConfirmed) {
        return;
    }
    const res = await axios.delete(`http://localhost:3000/heros/${id}`);
    if (res.status === 200) {
        this.loadData();
        alert('删除成功');
    } else {
        alert('删除失败');
    }
}

添加英雄

路由
  •   新建

    src/views/heroes/heroes-add.vue

  •   配置路由    

    import HeroesAdd from '../views/heroes/heroes-add.vue';

    // 增加一个路由规则
    {'name': 'heroesadd', path: '/heroes/add', component: HeroesAdd},
    {'name': 'heroes', path: '/heroes', component: Heroes},

  •   src/views/heroes/heroes.vue中点击添加按钮    

    <router-link class="btn btn-success" to="/heroes/add">Add</router-link>

HTML    

<h2 class="sub-header">添加英雄</h2>
<form>
    <div class="form-group">
        <label for="name">英雄名称</label>
        <input type="text" v-model="formData.name" class="form-control" id="name" placeholder="英雄名称">
    </div>
    <div class="form-group">
        <label for="sex">英雄性别</label>
        <input type="text" v-model="formData.gender" class="form-control" id="sex" placeholder="英雄性别">
    </div>
    <button type="submit" @click.prevent="handleAdd" class="btn btn-success">Submit</button>
</form>

   JS    

import axios from 'axios';

export default {
  data() {
    return {
      formData: {
        name: '',
        gender: ''
      }
    };
  },
  methods: {
    async handleAdd() {
      const res = await axios.post('http://localhost:3000/heros', this.formData);
      if (res.status === 201) {
        // 跳转到列表页面
        this.$router.push({
          name: 'heroes'
        });
      } else {
        alert('添加失败');
      }
    }
  }
};

编辑英雄

路由
  •   新建 src/views/heroes/heroes-edit.vue
  •   配置路由    

    import HeroesEdit from '../views/heroes/heroes-edit.vue';

    // 增加一个路由规则
    {'name': 'heroes', path: '/heroes', component: Heroes},
    {'name': 'heroesadd', path: '/heroes/add', component: HeroesAdd},
    {'name': 'heroesedit', path: '/heroes/edit/:id', component: HeroesEdit},

  •   src/views/heroes/heroes.vue中,设置编辑    

    <router-link :to="{name: 'heroesedit', params: {id: item.id}}">edit</router-link>

HTML

     和添加英雄一样

     JS    

import axios from 'axios';

export default {
  data() {
    return {
      formData: {
        name: '',
        gender: ''
      },
      heroId: -1
    };
  },
  created() {
    this.heroId = this.$route.params.id;
    this.getHeroById();
  },
  methods: {
    // 根据id,获取英雄信息
    async getHeroById() {
      const res = await axios.get(`http://localhost:3000/heros/${this.heroId}`);
      if (res.status === 200) {
        this.formData = res.data;
      }
    },
    // 更新英雄信息
    async handleEdit() {
      const res = await axios.patch(`http://localhost:3000/heros/${this.heroId}`, this.formData);
      if (res.status === 200) {
        // 跳转到列表页面
        this.$router.push({
          name: 'heroes'
        });
      } else {
        alert('编辑失败');
      }
    }
  }
};

NPM 缓存安装

需要曾经从网络使用NPM安装过想要的包    

$ npm --cache-min 9999999 install webpack --save-dev

----------------------------
原文链接:https://www.jianshu.com/p/77ea57cc82f1

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2021-02-14 18:54:42 重新编辑]
  Java面向对象编程-->对象的生命周期
  JavaWeb开发-->自定义JSP标签(Ⅱ)
  JSP与Hibernate开发-->Java对象持久化技术概述
  Java网络编程-->Socket用法详解
  精通Spring-->CSS过渡和动画
  Vue3开发-->Vue CLI脚手架工具
  qs.parse()、qs.stringify()、JSON.stringify() 用法及区别
  JavaScript实现睡眠函数
  vue 项目中使用loadsh 的 防抖(debounce)和节流(throttle...
  Thinking In Vue:vue指令的封装
  Vue自定义指令的用法
  JS对树形数据的遍历和过滤,
  H5定位终极解决方案
  jQuery与AJAX的整合简介
  JavaScript的HTML DOM Track 对象
  HTML的事件属性
  HTML标签的全局属性
  JavaScript的window.screen对象
  JavaScript 代码规范
  JavaScript 输出数据
  jQuery Mobile 安装
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。