vue相关--自己看看的

vue

一 : Vue 介绍

  1. vue 中文网
  2. github 下载地址
  3. Vue.js (读音 /vju:/ view)
  4. 渐进式 JavaScript 框架 3.1 渐进式 :

    小型项目 就可以使用 vue 就高度了 随着页面的复杂程序提高,就要学习 vue-rouer 来管理更多的页面 再随着项目的数据越来越多,管理数据也变得麻烦起来了,就开始使用 vuex 来管理数据

3.2 框架 : 一整套的解决方案

框架和库的区别 (面试-->控制翻转)

1. 库(Library) , 代表 : jquery
  • 库就是一系列函数的集合, 我们开发人员在使用库的时候,想要完成什么样的功能,就调用库中提供的某个方法

比如 : 想要添加样式, 就调用 jquery 中的 .css() / .addClass()

  • 库起到了一个辅助的作用, 在使用库的是时候,是由开发人员说了算, 也是由开发人员起主导作用.

比如 : 想给 A:设置样式 A.css(), B:addClass() C:style.background='red'

####2. 框架 (Framework), 代表:vue

  • 在使用框架的时候,是由框架说了算,由框架起到了主导作用,
  • 框架是一套完整的解决方案,框架中制定了一套规则,使用框架的时候,只需要按照规则,把代码放到合适的地方,然后框架会在合适的时机,主动调用开发人员的代码

比如 : 想用vue,组件里遍历就得使用 v-for, 下次不用 v-for 了,使用 for 不行 v-for='item in list'

3. 主要区别 : 控制反转

也就是 : 谁起到了主导作用

  • 使用库的时候 : 开发人员起主导作用
  • 使用框架的时候:框架起到了主导作用
  • 从体量上看,框架一般比库大
  • 会发现使用框架的时候,会受到很多限制
  • 我们所说的前端框架与库的区别?

三 : MVC + MVVM (面试)

第 3.1 MVC

  1. MVC 是一种软件架构模式,也有人叫做设计模式
  2. M : Model 数据模型 (专门用来操作数据,数据的 CRUD)
  3. V : View 视图 (对于前端来说,就是页面)
  4. C : Controller 控制器 (是视图和数据模型沟通的桥梁,用于处理业务逻辑)

第 3.2 MVVM

Vue 使用的是 MVVM 模式

  • MVVM ===> M / V / VM
  • M : model 数据层
  • V : view 视图层
  • VM : ViewModel 视图模型
  • 核心 : M <===> VM <===> V

第 3.3 MVVM 优势

  • MVC 模式 将应用程序划为三个部分,实现职责分离
    • 但是,在前端中,经常要通过 js 代码来进行一些逻辑操作,最终还要把这些逻辑操作展示页面中, 也需要频繁的操作DOM
    • 比如 : ajax 请求、添加、修改、设置样式、动画
  • MVVM 提出来的思想 通过 数据双向绑定 让数据自动的双向同步
    • V (修改视图) --> M
    • M (修改数据) --> V
  • 采用的是 : 数据驱动视图的思想, 数据是核心
  • 以后如果想要操作 DOM, 立马想到的不是应该是拿到元素设置,而是数据

第 3.4 Vue 中的 MVVM

  • 注意 : 不推荐直接手动操作 DOM

    每个人操作 DOM 的方法不一样,会造成性能不一样 官网 : 虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。

第 3.5 学习 Vue 要转化思想

  • 数据驱动视图 : 不要再想着怎么操作 DOM, 而是想着如何操作数据

四 : 起步 - Hello Vue

第 4.1 : 基本使用

  1. 安装 : npm i vue (小写)
  2. 导入 : <script src='./vue.js'></script>
  3. 实例 vue

const vm = new Vue({
  // 指定 vue 管理的边界
  el: '#app',
  // 提供视图中 需要的数据
  // 视图可以直接使用data中的数据
  data: {
    msg: 'xxx'
  }
})
复制代码

第 4.2 : 使用注意点

  1. vm 官网建议
  2. Vue 构造函数首字母大写
  3. 参数是一个对象
  4. id='#app', 其他也可以
  5. 边界外的无法使用 msg

4.3 {{}} 插值表达式

  1. {{}} Mustache 小胡子语法, 插值表达式
  2. 作用 : 使用{{}}data中获取数据,并展示在模板中
  3. 说明 : {{}} 中只能出现 js 表达式
  • 表达式 (有返回值的)
    • 常见的数据类型 1 'abc' false [] {}
    • 数据类型 和 运算符结合在一起1+2 arr.join('-') true ? 123 : 321
  • 语句 if语句 for语句
  1. {{}} 语法 不能作用在 HTML 元素的属性上
  2. 一般只有单标签dom元素不能够使用插值表达式

五 : 数据双向绑定演示

第 5.1 : 一个 input + v-model

 v-model 指令 : 数据双向绑定的指令
 作用 : 把data中的msg值 和  input上的值 绑定到一起
 注意 : v-model只能用在 表单控件上 (input checkbox 等)
 > 可以在浏览器分别演示 V => M  和 M =>V
复制代码

第 5.2 : Object.defineProperty

let obj = {}
let temp

obj.name = 'zhanhgsan'

// 参数1 : 要给哪个对象设置属性
// 参数2 : 给对象设置什么属性
// 参数3 : 属性的修饰符
Object.defineProperty(obj, 'name', {
  set: function(newVal) {
    console.log('赋值了', newVal)
  },
  get: function() {
    console.log('取值了')
    return temp
  }
})
复制代码

第 5.3 : 数据双向绑定的原理

  1. <input type="text" id="txt" />
  2. 演示 : V ==> M
//1. 拿到文本框
const txt = document.getElementById('txt')
//2. 时刻监听txt ,拿到最新的值
txt.oninput = function() {
  console.log(this.value)
  obj.name = this.value
}

//3. 数据模型
var obj = {}
let temp

Object.defineProperty(obj, 'name', {
  // 给属性赋值的时候会掉
  set: function(newVal) {
    console.log('调用了set', newVal)
    temp = newVal

    txt.value = newVal
  },
  get: function() {
    console.log('调用了get')
    return temp
  }
})
复制代码
  1. V => M
//1. 获取 input的值,最新值
//2. 通过监听oninput 拿到最新值
//3. 把最新值赋值给 obj.name
//4. 就会掉了set方法,就会修改了数据
复制代码
  1. M => V
//1. obj.name = 'xxx'
//2. 调用 set方法
//3. 把值赋值给input元素
复制代码

六 : 指令学习

第 6.0 指令

  • 指令 : 就是一个特殊的标记, 起一个辅助作用, 使 html 具备原来没有的功能
  • vue 中 所有的指令, 都是以 v-开头的
  • 比如 : v-model v-bind v-if v-for 等等

第 6.1 v-model (常用)

说明 : 用在表单元素中, 用来实现数据双向绑定 (input checkbox 等等) 作用 : 将 数据txt文本框的值 绑定到一起, 任何一方发生改变,都会引起对方的改变 注意 : v-model 在不同类型的表单元素中,该指令的作用不同

<!-- 文本输入框 绑定的是值 -->
<input type="text" v-model="txt" />
<!-- 多选框、按钮  绑定的选中状态 -->
<input type="checkbox" v-model="isChecked" />
复制代码

第 6.2 v-text 和 v-html

说明 : 设置文本内容

  1. v-text : 相当于之前的 innerText , 设置文本内容(不识别 html 标签) == 标签内部{{}} ===》注意v-text会完全替换掉标签里的内容
  2. v-html : 相当于之前的 innerHTML , 设置文本内容(识别 html 标签)
  3. 数据
   msg1: '<a>这是一条信息</a>',
   msg2: '<a href="#">我也是一条信息</a>'
复制代码

第 6.3 v-bind (常用)

说明 : 动态绑定数据 (单向) 出现原因 : 在 HTML 属性中, 无法使用插值表达式 步骤:

// 加载静态数据
 <a href="https://wbaidu.com">aaa</a>
// 想加载动态数据  {{ }}可以获取data中的数据
// 但是 {{}} 不能使用在属性中
<a href="{{ src }}">aaa</a>
// 所以使用v-bind
<a v-bind:href="{{ src }}">aaa</a>   ok
 <img v-bind:src="src">   ok
复制代码

缩略 : v-bind 全部省略 只留下一个: 改为 :

<a :href="src">aaa</a> ok
<img :src="src" /> ok
复制代码

以后 使用 静态加载数据 : <a href="https://wbaidu.com">aaa</a> 动态加载数据 : <a :href="href">aaa</a>

第 6.3.1 v-bind 和 v-model 的区别

//  v-model :  数据双向绑定         表单元素上
//   :      :  动态绑定数据(单向)    任意元素动态读取属性

容易出错点 : 
<!-- v-model 数据双向绑定 -->
<!--场景 :  表单元素中 -->
<input type="checkbox" v-model="isChecked1" /> <br />
<!--  v-bind 数据动态绑定 (单向) -->
<!--场景 :  主要用在属性中 -->
<input type="checkbox" :checked="isChecked2" />*
复制代码

第 6.4 操作样式

1.操作样式

<!-- 1. 静态类名 -->
<h1 class="red">哈哈</h1>

<!-- 2. 动态类名 -->
<h1 :class="cls">哈哈</h1>

<!-- 3. 最常用 -->
<!-- :class 里的值是一个对象 
      键 : 类名 (可能会要,也可以不要)
      值 : 布尔值, true/false 确定类要不要
     -->
<h1 :class="{ red:isRed , fz:isFZ}">哈哈</h1>

<!-- 4. style -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>
复制代码

2.其他操作

<!-- 1 -->
<!-- 重点 -->
<div :class="{ active: true }"></div>
===>
<div class="active"></div>

<!-- 2 -->
<div :class="['active', 'text-danger']"></div>
===>
<div class="active text-danger"></div>

<!-- 3 -->
<div :class="[{ active: true }, errorClass]"></div>
===>
<div class="active text-danger"></div>

--- style ---
<!-- 1   -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>
<!--  fz : 80 -->

<!-- 2 将多个 样式对象 应用到一个元素上-->
<!-- baseStyles 和 overridingStyles 都是对象 -->
<!-- 如果有相同的样式,以后面的样式为准 -->
<div :style="[baseStyles, overridingStyles]"></div>
复制代码

第 6.5 v-on 指令

注册事件/绑定事件

  1. v-on:click 绑定了一个单击事件

    : 后面是事件名称

<button v-on:click="fn">按钮</button>
复制代码
  1. 缩写 : @click='fn' <button @click='fn'>按钮</button>

  2. 函数写在 methods 里面

fn : function(){ ... }
fn() { ... }
复制代码
  1. 函数里面的 this 指的就是 vm 实例
> 在函数里面操作数据
- 获取数据  this.msg
- 修改数据  this.msg = 'XXX'
复制代码
  1. 传参 5.1 正常传参
@click='fn(123)'
复制代码

5.2 事件对象 $event

<!-- 4.1 绑定事件对象的时候, 没有添加小括号,此时,直接在方法中,通过参数 e 就可以获取到事件对象 -->
<!-- 4.2 如果添加小括号,就拿不到事件对象了,vue留了一个$event -->
<button @click="fn1($event,123)">我是按钮</button>
复制代码

6.5 v-for

  1. v-for 指令: 遍历数据,为数据中的每一项生成一个指令所在的标签
  2. 代码
<!-- 需求1 : 最常用 遍历数组 -->
<!-- 作用 : 遍历 list1 数据, 为数据中的每一项生成一个li标签 -->
<!-- item 数组里的每一项元素 -->
<ul>
  <li v-for="(item,index) in list1">{{ item }} - {{ index }}</li>
</ul>
<!-- 需求2 : 遍历元素是对象的数组 -->
<ul>
  <li v-for="item in list2">{{ item.name }} - id:{{ item.id }}</li>
</ul>

<!-- 需求3 : 遍历对象 -->
<ul>
  <li v-for="(item,key) in obj">{{ item }}-{{key}}</li>
</ul>

<!-- 需求4 : 想要生成10个h1 -->
<h1 v-for="item in 10">我是h1 {{ item }}</h1>
复制代码
  1. 重点是遍历数组,,其他的了解即可

    注意用v-for更新已经渲染过的元素列表的时候,他会默认就地复用策略,如果数组的顺序发生改变,vue不会一定dom元素来匹配顺序,而是简单的复用此处的每个元素,这样每个节点的状态就会对应不上

    解决这时候就需要给每个列表元素提供一个key,这个key需要是唯一的,以保证vue能准确的追踪到每个节点,key最好是列表中每项的id

七 : TODOMVC

###一 : 准备工作

  1. Vue-TodoMVC

  2. 演示效果 :

  3. 当前任务:敲代码、视频、游戏

  4. 下载模板地址

    git clone https://github.com/tastejs/todomvc-app-template.git

  5. 安装依赖包 : npm i

二 : 配置 vue

  1. 安装 vue : npm i vue

  2. 导入 vue : <script src="./node_modules//vue/dist/vue.js"></script>

    index.html里的app.js 导入之前导入,因为 app.js 里 就要用到 vue 了

  3. 实例化 vue :在app.js中创建 vue 示例,并设置好边界 el:'#app'

    找到 index.html ,给 section 标签添加一个 id

  4. 测试 vue :

    data 中随便来一个 msg 看能不能显示到视图中

生命周期函数

  • 所有的 vue 组件,都是 vue 实例, 一个组件对应一个实例,并且接收相同的选项对象(一些根实例特有的选项除外)
  • 实例生命周期也叫做 : 组件生命周期

这里先甩一张图

![](D:\study\笔记\我的整理\images\vue\Vue实例生命周期图 - 新版.png)

生命周期介绍

vue 生命周期钩子函数

  • 简单说 : 一个组件(实例) 从开始到最后消灭所经历的各种状态,就是一个组件(实例)的生命周期
  • 生命周期钩子函数的定义 : 从组件被创建,到组件挂在到页面上运行,再到页面关闭组件被销毁,这三个阶段总是伴随着组件各种的事件,这些事件,统称为组件的生命周期函数 (简称 : 钩子函数)
  • 开发人员可以通过 vue 提供的钩子函数,让我们写的代码参与到 vue 的生命周期里面来,让我们的代码在合适的阶段起到相应的作用

#####注意 :

  1. 注意 : vue 在执行过程中 会自动调用 生命周期钩子函数, 我们只需要提供这些钩子函数即可
  2. 注意 : 钩子函数的名称都是 vue 中规定好的

学习 vue 组件生命周期 学什么?

  1. Vue 内部执行的流程(难)
  2. 钩子函数如何使用 (两个重要的钩子函数 created mounted)

钩子函数 - beforeCreate

  • 说明 : 在实例初始化之前,数据观测 和 event/watcher 事件配置之前被调用

  • 组件实例刚被创建,组件属性计算之前, 例如 data 属性 methods 属性

  • 注意 : 此时,无法获取 data 中的数据 和 methoids 中的方法

  • 场景 : 几乎不用


钩子函数 - created (掌握)

  • 说明 : 组件实例创建完成,属性已绑定, 可以调用 methods 中的方法、可以获取 data 值

  • vue 实例生命周期 参考 1

  • vue 实例生命周期 参考 2

  • 使用场景 : 1-发送 ajax 2-本地存储获取数据

  • beforeCreate() {
        // 无法获取数据和事件
        console.warn('beforeCreate', this.msg, this.fn)
    },
    created() {
      console.warn('created', this.msg, this.fn)
    },
    复制代码

Has 'el' option ?

  1. YES => 就是正常的 el 边界
  2. NO => 可以注释,但是必须要手动添加 vm.$mount(el) 去指定边界
vm.$mount('#app')
复制代码

Has template option?

  1. No => 将 el 的 outerHtml 作为模板进行编译 ( outerHTML = 自身 + innerHTML )
  2. YES =>
 // 如果提供了 template, 那么 vue 就会将 template 的内容进行编译,编译后,替换页面中 vue 管理的边界
   template : `
      <h1>嘻嘻</h1>
   `,
复制代码

钩子函数 - beforeMounted()

  • 说明 : 在挂载开始之前被调用 (挂载:可以理解DOM 渲染)

钩子函数 - mounted() (掌握)

  • 说明 : 挂载之后, DOM 完成渲染

  • 使用场景 : 1-发送 ajax 2-操作 DOM

  • 记得把template去掉 
    // 渲染DOM之前
     beforeMount() {
         // 渲染之前的  <h1 id="h1" @click="fn">{{ msg }}</h1>
       console.log(document.getElementById('h1'))
     },
     // 渲染DOM之后  <h1 id="h1">测试</h1>
     mounted() {
       console.log(document.getElementById('h1'))
     }
    复制代码

钩子函数 - beforeUpdated()

  • 说明:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。

  • 注意:此处获取的数据是更新后的数据,但是获取页面中的 DOM 元素是更新之前的

    小提示 : 打印 this.$el ,打开小三角是之后的,是因为打印是有监听的功能,展示的是后面更改之后的


钩子函数 - updated()

  • 说明:组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。

  • beforeUpdate() {
        // 更新之前的值  :  信息
      console.warn('beforeUpdate', document.getElementById('h1').innerText)
    },
    updated() {
        // 更新之后的值 : 信息1111
      console.warn('updated', document.getElementById('h1').innerText)
    }
    复制代码

钩子函数 - beforeDestroy()

  • 说明:实例销毁之前调用。在这一步,实例仍然完全可用。
  • 使用场景:实例销毁之前,执行清理任务,比如:清除定时器等
  created() {

   this.timerId =   setInterval(() => {
      console.log(1111);

      }, 500);
   },

 // 如果当组件销毁了,还不清除定时器会出现性能问题
 // 在浏览器中可以尝试销毁  vm.$destroy()
 // 最后销毁
beforeDestroy() {
      clearInterval(this.timerId)
 },
复制代码

钩子函数 - destroyed()

说明:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。


使用钩子函数来完善 数据存储

created {
    this.list = localStorage.getItem('list')
}
复制代码

使用接口的形式发送数据

一 : json-server 提供假数据接口

  1. json-server 作用 : 根据指定的 JSON 文件, 提供假数据接口

  2. 地址 : json-server

  3. 使用步骤

    1. 全局安装 json-server  : `npm i -g json-server`
    2. 准备一个json数据
    3. 执行 :  `json-server data.json`
    
    > json数据参考
    json数据可以参考 :
    {
      "todos": [
        {
          "id": 1,
          "name": "吃饭",
          "age": 20
        }
      ]
    }
    复制代码
  4. REST API 格式

* 1. 查询 : GET
* 2. 添加 : POST
* 3. 删除 : DELETE
* 4. 更新 : PUT 或者 PATCH(打补丁)
复制代码
  1. 具体接口
* 1. 查询全部数据 http://localhost:3000/todos
*    查询指定数据 http://localhost:3000/todos/2
*
*  2. 添加一个对象 //localhost:3000/todos
*     POST
*     id 会自动帮我们添加
*
* 3. 更新数据 http://localhost:3000/todos/3
*    PUT 或者 PATCH
*    PUT 需要提供该对象的所有数据
*    PATCH 只需要提供要修改的数据即可
*
* 4. 删除数据
*    http://localhost:3000/todos/3
*    DELETE
复制代码
  1. 可以借助 postman 测试接口;

二 : axios 发送请求 (重点掌握)

读音 : /艾克笑丝/

  1. 作用 : 一个专门用来发送 ajax 请求的库, 可以在浏览器或者 node.js 中使用

    Promise based HTTP client for the browser and node.js
    	以Promise为基础的HTTP客户端,适用于:浏览器和node.js
    	封装ajax,用来发送请求,异步获取数据
    复制代码
  2. 使用步骤

    1. 本地安装 axios : `npm i axios`
    2. 导入 axios
    3. 使用
    复制代码
  3. axios 使用说明

  4. GTE 方式发送请求

    // 方式1
    axios.get('http://localhost:3000/todos/3').then(res => {
      console.log('获取到数据了:', res.data)
    })
    // 方式2
    axios
      .get('http://localhost:3000/menus', {
        params: {
          id: 003
        }
      })
      .then(res => {
        console.log('获取到数据了:', res.data)
      })
    复制代码

    5、 POST 方式发送请求

         // post 请求
         axios
             // 第一个参数:表示接口地址
             // 第二个参数:表示接口需要的参数
             .post('http://localhost:3000/todos', {
               name: 'axios添加数据',
               done: true
             }).then ( res =>  打印 res)
    复制代码
  5. 使用axios测试 todos 的几种接口

     //1. GET
      // 没有参数
      axios.get('http://localhost:3000/todo').then(res => {
        console.log(res)
      })
      // 有参数
      axios.get('http://localhost:3000/todo/1').then(res => {
        console.log(res)
      })
      axios
        .get('http://localhost:3000/todo', {
          params: {
            id: 2
          }
        })
        .then(res => {
          console.log(res)
        })

      // 2. POST
      axios
        .post('http://localhost:3000/todo', {
          name: 'XXX',
          age: 1
        })
        .then(res => {
          console.log(res)
        })

      //3. 删除
      axios.delete('http://localhost:3000/todo/8', {}).then(res => {
        console.log(res)
      })

      //4. 更新 - put
      axios
        .put('http://localhost:3000/todo/2', {
          name: '111',
          age: 300
        })
        .then(res => {
          console.log(res)
        })

      // 4. 更新 - patch
      axios
        .patch('http://localhost:3000/todo/1', {
          age: 3000
        })
        .then(res => {
          console.log(res)
        })
复制代码

三 : 完善 TodoMVC

  1. 获取全部

    axios.get('http://localhost:3000/list').then(res => {
        console.log(res.data);
        this.list = res.data;
    });
    复制代码
  2. 删除任务

    axios.delete('http://localhost:3000/list/' + id).then(res => {
        this.list = this.list.filter(item => item.id !== id);
        console.log(res);
    });
    复制代码
  3. 添加任务

    # id 会自动加
    axios
        .post('http://localhost:3000/list', {
        name: todoName,
        done: false
    })
        .then(res => {
        console.log(res.data);
        this.list.push({
            // 属性名 和属性值 一样的话,,可以省略一个
            id,
            name: todoName,
            done: false
        });
    });
    复制代码
  4. 更新任务 (在 hideEdit 里实现)

    # 难点1 : 在 hideEdit 这个方法里
    # 难点2 : 获取的这个id 就是editId
    hideEdit(e) {
    
    axios.patch('http://localhost:3000/list/' + this.editId, {
        name: e.target.value
    }).then(res => {
        console.log(res);
    
        this.editId = -1;
    })
    
    },
    复制代码
  5. 删除已经完成 的

    # 因为 这个假接口没有实现以下删除 完毕
    clearCompleted() {
        // 清除已经完成的,,只需要过滤出来未完成的即可
    
        let arr = this.list.filter(item => item.done);
        arr = arr.map(item => item.id);
    
        for (let i = 0; i < arr.length; i++) {
            axios.delete('http://localhost:3000/list/' + arr[i]).then(res => {
                this.list = this.list.filter(item => item.id != arr[i]);
            });
        }
    },
    复制代码
  6. 点击修改状态

    # 单独给 checkbox 都注册点击事件
    clickBox(id) {
        let todo = this.list.find(item => item.id == id);
    
        axios.patch('http://localhost:3000/list/' + id, {
            done: !todo.done
            }).then(res => {
            console.log(res);
            });
    }
    复制代码

单页面应用程序

  • SPA : Single Page Application
  • MPA : Multiple Page Application 多页面应用程序
单页web应用,
  就是只有一个web页面的应用,
  是加载单个HTML页面,
  并在用户与应用程序交互时动态更新该页面的web应用程序
复制代码
  • 区别
对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面

对于单页应用程序来说,
  只有第一次会加载页面,
  以后的每次请求,
  仅仅是获取必要的数据.然后,
  由页面中js解析获取的数据,
  展示在页面中
复制代码
  • 单页面优势 :
    1. 减少了请求体积,加快页面响应速度,降低了对服务器的压力
    2. 更好的用户体验,让用户在 web app 感受 native app 的流畅, (局部刷新)
  • 单页面劣势 :
    1. 开发成本高
    2. 不利于SEO
  • 演示 : music.163.com/

组件 (重难点)

一 : 组件化开发

  • 概念 :将一个完整的页面,抽离成一个个独立的组件,最终,通过这一个个独立组件完成整个的页面(项目)的功能
  • 组件化开发的优势/作用 : 复用
  • 官网 : 组件是可复用的 Vue 实例

二 : 组件的基本使用

  1. Vue 中的两种注册组件的方法 1.全局注册 2.局部注册

    全局组件在所有的vue实例中都可以使用
    局部组件在所有的当前实例中可以使用
    复制代码
  1. 注册全局组件 - 基本使用 1
/**
 * 第一个参数 : 组件名
 * 第二个参数 : 是一个配置对象, 该配置对象与 Vue 实例的配置对象几乎完全相同
 *        也就是说: vue实例中用到的配置项,和组件中的配置项几乎相同
 */
Vue.component('hello', {
  template: `
      <h1 class="red">这是hello组件</h1>
      `
})
复制代码
  1. 注意点
  • 注册全局组件也是放到 vm 实例之前
  • 模板只有一个根节点
  • 组件的配置项和 vue 实例 的配置项一样 (如:data、methods、filters、watch、computed、钩子函数等)
  • 组件的 data 是一个函数 返回一个对象
      var Component = function() {}
      // 使用对象
      Component.prototype.data = {
        demo: 123
      }
      // 使用函数
      Component.prototype.data = function() {
        return {
          demo: 111
        }
      }
      var component1 = new Component()
      var component2 = new Component()
      component1.data().demo = '8888'
      console.log(component2.data().demo) // 456
复制代码

示例:

 <h1 @click='fn' class="red">这是hello组件</h1>
  methods: {
          fn() {
            console.log('fn')
          }
        },
        computed: {},
        watch: {},
        filters: {}
}
复制代码

三: 改造 TodoMVC 成 组件化结构

  1. 安装 vue + 实例化
  2. 创建一个 components 文件夹
  3. 具体步骤
  • 创建一个 todo-head.js
  • 导入 <script src="./components/todo-head.js"></script>
  • 使用 <todo-head></todo-head>

四 : 组件通讯 (介绍)

  • 组件是一个独立、封闭的个体
  • 也就是说 : 组件中的数据默认情况下, 只能在组件内部使用,无法直接在组件外部使用
  • 可以将 vue 实例看做一个组件
  • 对于组件之间需要相互使用彼此的情况,应该使用 组件通讯 机制来解决
  • 组件通讯的三种情况 :
  1. 父组件将数据传递给子组件(父 -> 子)
  2. 子组件将数据传递给父组件 (子 => 父)
  3. 非父子组件(兄弟组件)

五 : 父 ==> 子 (重点) 两步

  1. 将要传递的数据,通过属性传递给子组件
<child :msg="pmsg"></child>
复制代码
  1. 子组件通过 props 配置项,来指定要接收的数据
props: ['msg']
复制代码

完善 TodoMVC => 完成 传值 + 渲染列表页

六 : 子 ==> 父 (重点) 三步

1 父组件中提供一个方法

pfn(arg) {

    console.log('父组件中接受到子组件传递过来的数据:', arg)
 }
复制代码

2 将这个方法传递给子组件

// 自定义事件 <child @fn="pfn"></child>
复制代码

3 子组件调用这个方法( 触发父组件中传递过来的自定义事件 )

// 这个方法是点击事件触发的
 handleClick() {
    // 调用父组件中的方法 fn
    // 注意:通过 $emit 方法来触发事件 fn
    // 第一个参数:表示要触发的自定义事件名称,也就是 @fn
    // 第二个参数:表示要传递给父组件的数据
    this.$emit('fn', 'child msg')
}
复制代码

完善 TodoMVC => 完成 传值 +添加+ 删除+清除完成

七 : 目前为止存属性的地方

  1. data
  2. 计算属性
  3. props

八 : 单向数据流(组件与组件之间) (了解)

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。 看图 当 todo-head 中的 todoName 设置数据后回车添加到 todoList,todoList 的长度就会发生变化, 然后就会根据(组件与组件之间的)单向数据流,把数据单向下流到子组件中 而且必须是通过 props 往下传递的才可以

props 的特点 : 只读

  1. 验证 props 只读

  2. 正常下是不需要子组件修改父组件传过来的值的,但是.....

  3. 修改父组件传给子组件的数据

    思路 : 把接收过来的数据,保存到 data 中一个临时值

  Vue.component('child', {
        template: `
      <div>子组件 {{ cmsg }} </div>
       `,
        data() {
          return {
            cmsg: this.msg
          }
        },
        props: ['msg'],
        created() {
          this.cmsg = 666
        }
      })
复制代码

prop 的大小写

  1. 官 : HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。

    html 的标签和 属性 都是一样,忽略大小写 <H1 TITLE="哈哈">我是h1</H1>

  2. 官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名不好使了

  • <child :cMsg="pmsg"></child> 会报警告,父传子也接收不到了
  • 原因是 : 接收的属性是:cMsg, 接收的数据名,因为忽略大小写,数据已为 : cmsg
  • 所以已经准备要读取的 是 cmsg 的值,找不到,所以要报警告 You should probably use "c-msg" instead of "cMsg".
  1. 方式 1 : 全用小写,不要使用驼峰命名

    接收 : cmsg props/读取 :cmsg

  2. 方式 2 官 : 需要使用其等价的 kebab-case (短横线分隔命名) 命名:

    接收 : :c-msg='pmsg' props/读取 : cMsg

九 : 完善 TodoMVC : 底部隐藏+剩余完成数+清除完成

计算属性 : 已知值(todoList 在 根组件) ==> 得到一个新值(子组件里使用)

父 => 子通讯

十 : 非父子之间通讯 ( 组件 => 组件 ) (重点)

需求 : 组件 jack ===> 恁弄啥哩 ===> 组件 rose

  • 是通过 事件总线 (event bus 公交车) 的机制 来实现的
  • 事件总线 : 实际上就是一个 空Vue实例
  • 可以实现任意两个组件之间的通讯,而不管两个组件到底有什么样的层级关系
  • 看图
  • 示例 :
// 第一步 : 事件总线
var bus = new Vue()

// 第二步 : 发送数据   可在点击事件里 触发事件
// 参数1 : 唯一标识  参数2:参数
bus.$emit('todo', '恁弄啥哩?')

// 第三步 : 接收数据    可在 created 里 注册事件
bus.$on('todo', arg => {
  console.log('接收过来的', arg)
})
复制代码

十二 : 注册局部组件

  • 局部组件只能在当前父组件的模板中使用
  • 不能再其他子组件里的子组件里显示
  • 示例 :
// 注册局部组件:
components: {
  // child表示组件名称
  // 值为配置对象,与 Vue.component 中的第二个参数相同
  // 注意:子组件child属于 Vue实例,因此,只能在 Vue实例的模板中使用
  child: {
    template: `
            <div>这是局部组件 child</div>
          `
  }
}
复制代码

十三 : 获取组件(或DOM元素) - refs

  • 说明 : vm.$refs 一个对象, 持有已注册过 ref 的所有子组件 ( HTML 元素)

  • 使用 :

    1. 注册
    // 标签
    <div ref="div">哈哈</div>
    // 组件 
    <child ref="child"></child>
    复制代码
    1. js 中使用
    // mounted 操作DOM
    * this.$refs.div
    * this.$refs.child
    
    复制代码
  • 注意点 : 如果获取的是一个子组件,那么通过 ref 就能获取到子组件中的 datamethods

    this.$refs.child.num
    this.$refs.child.fn
    复制代码
  • 场景 : 一般在第三方的组件中, 可能会用到这个功能

  • 示例 :

// 组件
 <div ref="div">哈哈</div>
 <child ref="child"></child>
// js
 mounted() {
    console.log(this.$refs.div)
    console.log(this.$refs.child.fn)
  }
复制代码

单页面应用与路由

单页面应用程序

  • SPA : Single Page Application
  • MPA : Multiple Page Application 多页面应用程序
单页web应用,
  就是只有一个web页面的应用,
  是加载单个HTML页面,
  并在用户与应用程序交互时动态更新该页面的web应用程序
复制代码
  • 区别
对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面

对于单页应用程序来说,
  只有第一次会加载页面,
  以后的每次请求,
  仅仅是获取必要的数据.然后,
  由页面中js解析获取的数据,
  展示在页面中
复制代码
  • 单页面优势 :
    1. 减少了请求体积,加快页面响应速度,降低了对服务器的压力
    2. 更好的用户体验,让用户在 web app 感受 native app 的流畅, (局部刷新)
  • 单页面劣势 :
    1. 开发成本高
    2. 不利于SEO
  • 演示 : music.163.com/

路由

  • 路由 : 是浏览器 URL 中的哈希值( # hash) 与 展示视图内容 之间的对应规则
在 web App 中, 通过一个页面来展示和管理整个应用的功能.
SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生. (为什么要学习路由??)
简单来说,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.
当 URL 中的哈希值( `#` hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容
复制代码
  • vue 中的路由 : 是 hashcomponent 的对应关系, 一个哈希值对应一个组件

基本使用

    1. 安装路由 : npm i vue-router
    1. 引入路由
    <script src="./vue.js"></script>
    // 千万注意 :引入路由一定要在引入vue之后,因为vue-router是基于vue工作的
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
复制代码
    1. 详细使用步骤
  • 3.0 实例路由对象+挂载到 vue 上

    const router = new VueRouter() 路由实例 与 Vue 实例 关联到一起 验证路由是否挂载成功, 就看打开页面,最后面有没有个 #/

  • 3.1 入口 (#哈希值)

// 方式1 : url地址为入口   调试开发用
输入url地址 改变哈希值
`01-路由的基本使用.html#/one`

// 方式2 : router-link+to

复制代码
  • 3.2 设置路由规则
// path : 路由路径
// component : 将来要展示的路由组件
routes: [{ path: '/one', component: One }, { path: '/two', component: Two }]
复制代码
  • 3.3 组件

    一个哈希值对应一个组件

const One = Vue.component('one', {
  template: `
        <div> 子组件 one </div>
        `
})
复制代码
  • 3.4 出口
<!--  出口 组件要展示的地方-->
<router-view></router-view>
复制代码
  1. 分析执行过程(看图)

使用注意事项

  1. 入口(哈希)
  • 最常用的入口
<!-- 1. 入口 -->
<!-- 
    to 属性 , 实际上就是哈希值,将来要参与路由规则中进行与组件匹配
    router-link 组件最终渲染为 : a标签, to属性转化为 a标签的href属性
  -->
<router-link to="/one">首页</router-link>
复制代码
  1. 组件

    组件可以改为对象格式

const One = {
  template: `
        <div> 子组件 one </div>
        `
}
复制代码
  1. 过程 : 入口 ==> 路由规则 ==> 组件 ==> 出口

  2. 演示 : 多个组件匹配

    可以有多个入口,但只需要一个出口

  3. 示例 :

<div id="app">
  <!-- 1 路由入口:链接导航 -->
  <router-link to="/one">One</router-link>
  <router-link to="/two">Two</router-link>

  <!-- 4 路由出口:用来展示匹配路由视图内容 -->
  <router-view></router-view>
</div>

<!--  导入 vue.js -->
<script src="./vue.js"></script>
<!--  导入 路由文件 -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
  // 3 创建两个组件
  const One = Vue.component('one', {
    template: '<h1>这是 one 组件</h1>'
  })
  const Two = Vue.component('two', {
    template: '<h1>这是 two 组件</h1>'
  })

  // 0 创建路由对象
  const router = new VueRouter({
    // 2. 路由规则
    routes: [
      { path: '/one', component: One },
      { path: '/two', component: Two }
    ]
  })

  const vm = new Vue({
    el: '#app',
    //0. 不要忘记,将路由与vue实例关联到一起!
    router
  })
</script>
复制代码

复习一遍代码 + 流程

入口导航菜单高亮处理

  1. 点击导航发现代码有两个类 :
<a href="#/one" class="router-link-exact-active router-link-active">One</a>
<a href="#/two" class="">Two</a>
复制代码
  1. 修改方式 1 : 直接修改类的内容
.router-link-exact-active,
.router-link-active {
  color: red;
  font-size: 50px;
}
复制代码
  1. 修饰方式 2 : 修改默认高亮类名 (推荐)

    因为有时候项目中可能已经针对导航有过设置样式,后来再加的路由,所以如果再重新像方式 1 再加一次,会重复 所以 :可以 修改默认高亮的 a 标签的类名

const router = new VueRouter({
  routes: [],

  // 修改默认高亮的a标签的类名
  // red 是已经存在过的
  linkActiveClass: 'red'
})
复制代码

精确匹配和模糊匹配

  • 精确匹配 : router-link-exact-active 类名 : 只有当 浏览器地址栏中的哈希值 与 router-link 的 to 属性值,完全匹配对,才会添加该类
  • 模糊匹配: router-link-active 类名 : 只要 浏览器地址栏中的哈希值 包含 router-link 的 to 属性值,就会添加该类名
  • 解决办法 : 加个 exact
<router-link to="/" exact>
  One
</router-link>
复制代码
  • 注意 : 精确匹配和模糊匹配,只对添加类名这个机制有效,与路由的匹配规则无关!!!

路由参数

看图分析: 列表 => 详情组件

  1. 导航入口
<!-- 1. 入口  -->
<router-link to="/detail/1">手机1</router-link>
<router-link to="/detail/2">手机2</router-link>
<router-link to="/detail/3">手机3</router-link>
复制代码
  1. 传参: 最笨的方式
routes: [
  // 2 . 路由规则
  { path: '/detail/1', component: Detail },
  { path: '/detail/2', component: Detail },
  { path: '/detail/3', component: Detail }
]

//3. 组件
const Detail = Vue.component('detail', {
  template: `
      <div> 显示详情页内容....{{ $route.path  }} </div>
      `
})
复制代码
  1. 正确的方式 : 把传过去的 1/2/3 当成参数 3.1 路由规则的正确方式 :
routes: [
  // 2 . 路由规则
  { path: '/detail/:id', component: Detail }
]
复制代码

3.2 获取参数的三种正确方式

const Detail = Vue.component('detail', {
  template: `
       // 方式1 : 组件中直接读取
       <div> 显示详情页内容....{{ $route.params.id  }} </div>
        `,
  created() {
    // 方式2 : js直接读取
    // 打印只会打印一次,因为组件是复用的,每次进来钩子函数只会执行一次
    console.log(this.$route.params.id)
  },
  // 方式3 : 监听路由的参数变化 为什么不需要深度监听,因为它不是data中的
  watch: {
    $route(to, from) {
      console.log(to.params.id)
    }
  }
})
复制代码
  1. 如果输入的没有带参数的

    有参数的对应 : 下面都是正确打开方式

detail/1 ==> 显示详情页内容....1
detail/2 ==> 显示详情页内容....2
detail/3 ==> 显示详情页内容....3
复制代码

如果通过改变 url 地址,不输入参数 就看不到 显示详情页内容 这些字 说明没有正确匹配到 detail组件

  • 有可能不输入参数 :后面加个? 代表可传可不传
  • ** { path: '/detail/:id?', component: Detail }**
// 可识别的路径是这样的
* detail
* detial/1
* detial/2
* detial/3
复制代码
  1. 示例 :
// 链接:
<router-link to="/user/1001">用户 Jack</router-link>
<router-link to="/user/1002">用户 Rose</router-link>

// 路由:
{ path: '/user/:id', component: User }

// User组件:
const User = {
  template: `<div>User {{ $route.params.id }}</div>`
}
复制代码

重定向

  • 解释:将 / 重定向到 /home
{ path: '/', redirect: '/home' }
复制代码

子组件 (项目中讲)

Webpack

概念 ==> webpack 是什么?? 前端模块化打包(构建)工具

webpack可以解决这些依赖关系,并对他们进行打包

webpack 的两个方面

1 - 打包 2 - 模块化

一、打包 : 前端打包(构建)都能做什么??

  1. 语法转换

    - Less/SASS 预编译CSS -> CSS -> 浏览器中使用
    - ES6 新语法有兼容性问题 -> ES5 -> 浏览器中使用
    - const fn = () => {} ===> var fn = function() {}
    复制代码
  2. 文件压缩、合并

    JS/HTML/CSS 压缩后,才能发布上线
    文件合并( 不管有多个JS、CSS,默认打包直接生成一个JS文件 )
    复制代码
  3. 开发期间提供一个服务器环境

     自动打开浏览器、监视文件变化,自动刷新浏览器
    复制代码
  4. 项目上线,打包后才能上线

  5. 总结

     webpack 这个打包(构建)工具,就是提供了前端开发需要的一整套完整的流程,也就是
     webpack 能够渗透的前端开发的各个环节、各个流程中,帮你实现 复杂、繁琐、重复的工作,有了 webpack 后,开发人员只需要关注当前要实现的业务即可。
    复制代码

二、模块化功能

  • 模块化 : 逻辑

  • 组件化 : 界面

  • webpack为前端提供了模块化开发环境,而且webpack是基于node,有了webpack,就可以像写Node代码一样,写前端代码了

  • 在 webpack 看来所有的资源都是模块,不管是: CSS、图片、字体、JS、html 等

  • 在webpack提供的模块化环境中,
    1 想要加载一个JS文件,只需要 require('./a.js')
    2 想要加载一个CSS文件,只需要 require('../css/index.css')
    3 想要加载一个图片文件,只需要 require('../iamges/a.png')
    4 ...
    复制代码

Webpack 四个核心概念:

入口(entry)出口(output)加载器(loader)插件(plugins)

  • 入口 : 要打包哪个文件
  • 出口 : 要打包到哪里
  • 加载器 : 加载除了js文件其他文件的功能
  • 插件 : 处理加载器完成不了的功能, 使用插件

学习 手动配置 webpack 的目的

  • 为了我们后面使用脚手架做准备,
  • 能够完成webpack的基本安装
  • 能够了解webpack配置文件的作用
  • 能够说出webpack中loader 的作用
  • 能够使用webpack处理常见的资源(css/less/图片)
  • 能够说出webpack-dev-server的作用以及配置
  • 目标 : 能跟着 视频 + 笔记 照着敲完一遍即可

webpack 使用步骤 (最新版)

第一阶段

命名初始化阶段

文件名不能有汉字,不能取名叫 webpack

  1. 生成 package.json, 命令 : npm init -y
  2. 安装 : npm i -D webpack webpack-cli
webpack  : 是 webpack 工具的核心包
webpack-cli : 提供了一些在终端中使用的命令
-D(--save-dev) : 表示项目开发期间的依赖,也就是 : 线上代码中用不到这些包了
复制代码
  1. 创建一个main.js文件
console.log('我就要被打包了,哦也');
复制代码
  1. package.jsonscripts中,添加脚本
 "scripts": {
    "build": "webpack main.js"
  },
// webpack 是webpack-cli 中提供的命令, 用来实现打包的
// ./main.js 入口文件,要打包哪个文件
复制代码
  1. 运行 : npm run build
  2. 设置开发状态 : mode
"build" : "webpack ./main.js --mode development"

// WARNING in configuration
// The 'mode' option has not been set, webpack will fallback to 'production' for this value.
// 如果没有设置 mode 配置项, webpack 会默认提供 开发环境(production)

// Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
// 项目开发的两种环境
  1. 开发环境 (development) : 开发过程就是开发环境
  2. 生产环境 (production) : 线上环境, 也就是 : 项目做好了,发布上线
  生产环境下, 打包生产的js文件都是压缩后的,  开发环境下代码一般是不压缩的
复制代码

第一阶段 隔行变色案例

  1. 创建 src/index.html
  2. 隔行案例 => html => ul#list>li{我是 li \$}\*10
  3. 安装 juqery : npm i jquery, 并且引入 jquery
  4. 暂时引入 main.js , 在 main.js 里写入
// 使用ES6的模块化语法
import $ from 'jquery' // 优点 不用沿着路径去找

$('#list > li:odd').css('backgroundColor', 'red')
$('#list > li:even').css('backgroundColor', 'green')
// 语法报错
复制代码
  1. 问题 :
// 引入 main.js 会报错,因为浏览器不支持这个import 的Es6语法
// npm run build 之后
//  引入 dist/main.js 后会ok,因为webpack 帮我们转化为浏览器能够识别的es5语法了
复制代码
  1. 历程 :
//1. 如果index.html 中引入 jquery , 再引入 mian.js (没有引入jquery了) => ok
//2. 如果index.html 中没有引入 jquery , 直接使用es6的模块化语法 import , 引入main.js就会报错
//3. 如果index.html 中没有引入 jquery , 直接使用es6的模块化语法 import , webapck打包出 dist/main.js 引入 dist/main.js  ==> ok
复制代码
  1. 为什么 dist文件下的main.js 文件里的代码突然这么多

    看图 (打包流程)

  2. code 记得保存一份

第二阶段

配置文件

  1. 准备工作 : src源文件 : index.htmlmain.js

  2. webpack 打包有两种方式

    1-命令行 2-配置项

  3. 方式 1 : 命令行

*    "build"  : "webpack ./mian.js" --mode development
*     npm run build
*   一般情况下 : 改为
*     "build" : 入口  --output 出口
*     "build": "webpack ./src/js/main.js --output ./dist/bundle.js  --mode development",
*
*     验证 : index.html 引入 bundle.js
复制代码
  1. 方式 2 : 配置项
第一步 : 项目`根目录`下, 创建一个 `webpack.config.js`文件 (文件名固定死)
         专门指定其他文件 : --config  webpack.XX.js
第二步 : 在 `webpack.config.js` 中,进行配置
// webpack 是基于 node的 , 所以配置文件符合 node 方式书写配置
// 注意 : 不要再这个文件中使用ES6的的模块化 import语法
// main.js里可以使用,是因为要通过webpack转化为es5的
// 而这个是webpack 的配置文件,,它是要转化别人的,所以必须要通过
第三步 : 修改 `package.json` 中的 `scripts` , 脚本命令为: "build": "webpack"
第四步 : 执行命令 : `npm run build`
复制代码
  1. 示例代码(webpack.config.js) :
const path = require('path')

module.exports = {
  // 入口
  entry: path.join(__dirname, './src/js/main.js'),
  // 出口
  output: {
    // 出口目录
    path: path.join(__dirname, './dist'),
    filename: 'bundle.js'
  },
  // 开发模式
  mode: 'development'
}
复制代码
配置文件 html-webpack-plugin
  1. html-webpack-plugin 必备的插件
作用 :
  1. 能够根据指定的模板文件 (index.html),自动生成一个新的 index.html,并且注入到dist文件夹下
  2. 能够自动引入js文件
复制代码
  1. 安装 : npm i html-webpack-plugin
  2. 配置 :
第一步: 引入模块
const htmlWebpackPlugin = require('html-webpack-plugin')
第二步: 配置
// 插件
plugins: [
  // 使用插件 指定模板
  new htmlWebpackPlugin({
    template: path.join(__dirname, './src/index.html')
  })
]
复制代码
配置文件 : webpack-dev-server
  1. webpack-dev-server 使用 webpack 必备的功能(插件)

作用 : 为使用 webpack 打包提供一个服务器环境

  • 1.1 自动为我们的项目创建一个服务器
  • 1.2 自动打开浏览器
  • 1.3 自动监视文件变化,自动刷新浏览器...
  1. 使用步骤 :
  • 2.1 安装 : npm i -D webpack-dev-server
  • 2.2 两种使用方式: 1-命令行 2-配置文件(推荐)
  1. 方式 1 : 命令行配置
  • 脚本 : "dev" : "webpack-dev-server"
  • 运行到 npm run dev
  • 查看路径 : "http://localhost:8080/"
  • 「wds」: Project is running at http://localhost:8080/
  • 问题 1 : 自动打开?
  • 解决 : 添加 --open
  • 问题 2 : 指定端口号
  • 解决 : 添加 --port 3001
  • 问题 3 : 热更新
  • 解决 : --hot ( 整个页面和整个项目打包 )
  1. 方式 2 : 配置文件配置
// hot 不要写在配置文件里面,,不然的话还要配其他插件麻烦
 "dev" : "webpack-dev-server --hot",

  devServer : {
    open : true,
    port : 3001
  }
复制代码

第三阶段 项目打包上线的说明

  1. 开发模式 : npm run dev ==> 不会打包的 ,只会把项目放到服务器里
  2. 假设项目开发完成了,要上线,怎么操作?
2.1 执行 : `npm run build` 对项目进行打包,生成dist文件
2.2 模拟本地服务器 : 安装 : `npm i -g http-server`
2.3 把dist文件里的内容放到服务器里即可, 直接运行`http-server`
复制代码

第四阶段

打包非js文件

webpack 只能处理 js 文件,非 js(css.less.图片.字体等)处理处理不了, 借助 loader 加载器

1 : 处理 css 文件
  1. 创建一个 css 文件, 然后在 main.js中引入 import '../css/index.css';

    ul { style-list : none }

  2. 安装 : npm i -D style-loader css-loader

  3. webpack.config.js 中,添加个新的配置项 module

  4. module 中添加 loader 来处理 css

// loader
module: {
  rules: [
    //1.处理 css
      // 注意点 use执行loader 顺序 从右往左
      // css-loader  :  读取css文件内容,将其转化为一个模块
      // style-loader :拿到模块, 创建一个style标签,插入页面中
    { test: /\.css$/, use: ['style-loader', 'css-loader'] }
  ]
}
复制代码
2 : 处理 less 文件
  1. 创建一个 less 文件, 然后再 main.js 中 引入 import '../css/index.less';
  2. 安装 : npm i -D less-loader less style-loader css-loader
  3. 在 webpack.config.js 中, 配置 module->rules
  4. 在 module 中, 添加 loader 来处理 less
ul {
  background-color: aqua;
  li {
    &:hover {
      color: yellow;
    }
  }
}
复制代码
  1. 配置 :

     { test :/\.less$/, use : ['style-loader','css-loader','less-loader'] },
    复制代码
3 : 处理 图片 文件
设置背景图片

.cls {

width: 300px;

height: 300px;

background: url('../css/4.jpg');

background-size: 100%;

}

  1. 安装 : npm i -D url-loader file-loader

    url-loader (推荐) 和 file-loader 二选一即可

  2. 在 webpack.config.js 添加 loader 规则

// 处理图片
  { test : /\.(jpg|png)$/, use : ['url-loader'] },
复制代码
  1. url-loader 默认会将图片转化为 base64 编码格式, 目的:提高性能
  2. file-loader 在车里图片时, 会对文件进行重命名 :
原始:    background-image: url(../images/1.jpg);
处理后:  background-image: url(9c9690b56876ea9b4d092c0baef31bb3.jpg);
复制代码
  1. base64 编码格式的图片说明 :
  • 精灵图 : 将一些小图片合并为一张图片,减少请求次数,提高性能
  • 字体图标 :直接将一些小的图片,合并到字体文件中,并且不会失真
  • base64 : 是一种编码格式,能够将图片、文字等常见的文件,转化为 base64 格式,这种字符串格式, 浏览器能够识别并且读取显示到页面中;
  • base64 是一个字符串,也可以直接被内嵌到页面中, 或者 css 中
  • 注意 : 大图片不适合用 base64 处理, 只有小的图标才适合 base64 处理
  1. 设置配置
方式1 :{ test : /\.(jpg|png)$/, use : ['url-loader?limit=57417'] }, 
方式2 : 
{
        test: /\.(jpg|png)$/, use: [
          {
            loader: 'url-loader',
            options: {
              //  比57417这个小 => 转化为base64
              //  大于等于这个57417值 => 不会转base64 内部调用 file-loader 加载图片
              limit: 57417
            }
          }
        ]
      },
复制代码
4: 处理 字体 文件
  1. 准备字体图标: 字体图标文件 iconfont 或者 从阿里矢量图标里下载

  2. 拷贝到项目中的 css 文件夹中

  3. main.js 中引入 css 文件

    import '../css/iconfont/iconfont.css'
    复制代码
  4. 使用 :

  5. 在 webpack.config.js 中配置

 // 4. 处理字体图标
  { test:/\.(svg|woff|woff2|ttf|eot)$/,use:'url-loader'}
复制代码
5:处理 ES6 语法
  1. 现在的项目都是使用 ES6 开发的, 但是这些新的 ES6 语法, 并不是所有的浏览器都支持, 所以就需要有一个工具,帮我们转成 es5 语法, 这个就是: babel
  2. babel
  3. Babel is a JavaScript compiler. ==> babel 是一个 JavaScript 编译器
  4. webpack 只能处理 import / export 这个 es6 模块化语法 而其他的 js 新语法,应该使用 babel 来处理
  5. 比如 : var o = { ...obj } 在谷歌上可以,edge 就不可以
  6. babel 的使用 :
  • 6.1 安装 1 : npm i -D babel-core babel-loader@7
    • babel-core 是 babel 的核心包
    • babel-loader 加载 js 文件, 并将 js 代码内容交给 babel-core 解析为 es5 低版本的 js
  • 6.2 安装 2 : npm i -D babel-preset-env babel-preset-stage-2
    • babel-preset-* 表示能够解析什么版本的 js 语法
    • babel-preset-env : 表示能够解析 es2015,es2016,es2017,es2018 这些标准的语法
    • babel-preset-stage-2 : 用来解析经过会遇到,但是还没有被采纳为标准的语法
    • 比如 : 'abc'.padStart(10, '6') : 准备 10 位字符,有 abc,前面不够用 6 补充,是 es2017 的语法,
    • babel-polyfill与babel-plugin-transform-runtime 也是做兼容处理的,以前都是用这个,兼容更早的
  • 6.3 配置 : 在 webpack.config.js 中添加一个 loader
  { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
复制代码
  • 6.4 在项目根目录中创建 babel 的配置文件,叫:.babelrc
  {
  "presets": [
    "env",
    "stage-2"
  ],

  -----------
  // 暂时不用
  // 如果未来某一天真的用到了polify
    "plugins": [
        ["transform-runtime", {
                "helpers": false,
                "polyfill": true,
                "regenerator": true,
                "moduleName": "babel-runtime"
    }]
复制代码
  • 6.5 测试 : 谷歌 和 edge
var obj = {
  name: 'zs',
  age: 20
}

var o = { ...obj }
console.log(o)
复制代码

webpack中文链接

项目准备

一 : vue 是 单文件组件

直接注册组件的缺点

  • 语法不会高亮
  • 格式不好
  • 没有专门写css样式的地方

单文件组件

  1. 什么是单文件组件 ?=> 后缀为 .vue 的文件
  2. 单文件组件的三个组成部分 (代码块 : scaffold 自动提示)
  • template (模板结构)
  • script 组件的代码逻辑
  • style 样式
  1. 注意点 :
    • 单文件组件,无法直接在浏览器中使用,必须经过 webpack 这种打包工具,处理后,才能在浏览器中使用

二 : 脚手架 介绍

脚手架 2.X ==> 2.Xvue

脚手架 3.X ==> 3.X vue

  1. vue-cli 是 vue 的脚手架工具

  2. 作用 : vue-cli 提供了一条命令, 我们直接通过这条命令就可以快速的生成一个 vue 项目 (vue init XX) 。 项目的基本结构、以及 webpack 配置项 全部配置 好了

  3. 为什么会有脚手架工具 ???

    因为 webpack 配置繁琐, 阻止一批想用 vue 但是不会 webpack 的开发人员,所以作者直接将所有 vue 项目中用到的配置全部帮你写好了,这样,就不需要开发人员再去配置基础 webpack 配置项了,使用 vue-cli 这个脚手架工具后,再也不用担心 webpack 配置问题了, 我们前端只需要写 vue 代码, 来实现功能即可

三 : 脚手架工具使用

  • 安装 : npm i -g vue-cli
  • 初始化 vue 项目 : vue init webpack 项目名称
    • 比如 : vue init webpack vue-demo01
  • 项目安装过程 :
? Project name # 回车
? Project description # 回车
? Author  # 回车
? Vue build standalone  # => 运行时+编译 => 详见下面的问题1 
? Install vue-router? # Yes
? Use ESLint to lint your code? # Yes => 详见下面的问题2
? Pick an ESLint preset Standard  # standard
? Set up unit tests # No
? Setup e2e tests with Nightwatch? # No
? Should we run `npm install` for you after the project has been created? # (recommended) npm
复制代码
  • 如何开始
To get started:
cd vue-demo01
npm run dev
复制代码
  • "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    • --inline 意思是信息显示在哪里
    • -progress 进度条
    • 指定哪个文件作为 webpack 的配置文件 开发的

四 : 文件项目介绍

第一遍:文件夹, 第二遍再细化文件

# build - webpack 相关配置

- build.js - 生产环境构建代码
- check-version.js 检查 node、npm 等版本
- util.js 构建工具相关
- vue-loader.config.js vue-loader 的配置文件
- webpack.base.conf.js - webpack 的基础配置
- webpack.dev.conf.js - webpack 开发环境配置
- webpack.prod.conf.js - webpack 发布环境配置

# config - vue 基本配置文件(比如:监听端口(17), 使用 eslint:(26))

- dev.env.js - 开发环境变量
- index.js 项目的一些配置
- prod.env.js 生成环境变量

# node_modules - node 安装的依赖包

# src - 资源文件夹, 以后我们就在这个目录下写代码

- assets - 静态资源 (图片 css 都放在这)
- components - 公用组件
- router - 路由
- App.vue - 项目的根组件
- main.js - 项目的入口文件(总逻辑)

# static - 静态资源 (图片 json 数据之类的)

- .gitkeep git 保持文件,因为 git 上传,会忽略空文件夹

# .babelrc - babel 配置文件, (es6 语法编译配置,将 es6 转化为浏览器能够识别的代码)

# .editorconfig - 定义代码格式

- charset = utf-8 编码 utf8
- indent_style = space 缩进 空格
- indent_size = 2 缩进字符
- end_of_line = lf 回车作为换行的标记
- insert_final_newline = true 最近一空白行作为结尾
- trim_trailing_whitespace = true 清除最开始的空白
- 如果使用 ?
- 1. 安装 vscode 的 editorConfig for vscode
- 2. eslint 检测修复后

# .eslintignore - eslint 检测忽略的地方

- /build/
- /config/
- /dist/
- /\*.js 根目录下带.js 的

# .eslintrc.js - eslint 的配置文件

# .gitignore - git 的忽略文件

# .postcssrc.js - css 配置文件 (啥也没有处理)

# index.html - 页面入口

# package.json - 项目配置文件

复制代码

4.1 参考 : standard

4.2 参考 : src

  • assets 静态资源

  • components 组件

  • App.vue 根组件 => 指定路由出口

    • 脚手架之后,所有的组件都将渲染到 app.vue 中
  • app 中的 #app 还是 index.html 中的 #app, app.vue 中的会覆盖前者 可以通过分别添加 title 属性验证一下

  • 路由出口要写在 app.vue 组件模板中

  • main.js

    • 入口 js 文件
    • 作用 : 创建 vue 实例,导入其他组件并挂在到 vue 实例上
    • Vue.config.productionTip = false 不要打印提示
    • 检测 no new : 见后面的检测警告
    new Vue({
      el: '#app', // 目标显示
      router,   // 挂载路由
      components: { App }, // 注册组件 App
      template: '<App/>' // 模板显示组件 app
    })
    复制代码
  • route/index.js => 路由

  • 一定要记住 :Vue.use(Router) 模块化公工程中一定要安装路由插件 .js 就是一个模块

  • 官网里 也提到 https://router.vuejs.org/zh/installation.html

五 : 问题处理

5.1 - 问题1 : 两种编译模式 和 @

参考 : vue.js => 安装 => 对不同构建本版本的解释

  • 我们选择的是 Runtime + Compiler 模式 : ( 运行时 + 编辑器)
  • 运行时模式 : 用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切。
  • 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。
// 需要编译器
new Vue({
  template: '<div>{{ hi }}</div>'
})

// 不需要编译器
new Vue({
  render (h) {
    return h('div', this.hi)
  }
})
复制代码
  • 完整版版本选用 : ES Module (基于构建工具使用) : vue.esm.js
    • build => webpack.base.config.js => 37 行 alias(别名) 'vue$': 'vue/dist/vue.esm.js',
  • @ : 就是src的绝对路径
    • build => webpack.base.config.js => 38 行 alias(别名) '@': resolve('src'),
router/index.js =>
	import HelloWorld from '@/components/HelloWorld'
	import HelloWorld from 'C:/users/.../src/components/HelloWorld'
复制代码

5.2 - 问题2 : ESLint

  • 概念 : ESLint 是在 JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。

    • 在 vscode等编辑工具 中, 可以提示语法错误
    • 在许多方面,它和 JSLint、JSHint 相似,除了少数的例外:
  • 如何使用 eslint ?

    • 1-安装vscode插件 ESlint
    • 2-vscode设置里添加一些配置
     "editor.formatOnSave": true, //#每次保存的时候自动格式化
      "eslint.autoFixOnSave": true, // #每次保存的时候将代码按eslint格式进行修复
      "eslint.validate": [
        { "language": "html", "autoFix": true },
        { "language": "vue", "autoFix": true },
        { "language": "javascript", "autoFix": true },
        { "language": "wpy", "autoFix": true }
      ],
      "prettier.eslintIntegration": true, // #让prettier使用eslint的代码格式进行校验
      "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
      "editor.formatOnType": true //#让函数(名)和后面的括号之间加个空格
    复制代码
  • 关闭 Eslint :

    • 参考 : config/index.js ==> 26行 : dev.useEslint 设置为false
    • 重启项目: npm run dev
    • 测试 : 删除 main.js 中的 /* eslint-disable no-new */ 关闭后 会报波浪线,但是不会报错了

5.3 问题3 : vscode安装 格式化插件 Prettier

  • 安装 vscode 插件 Prettier
  • 功能1 : shift + alt + F => 格式化代码
  • 功能2 : 配合 eslint : 见上一个问题的配置

5.4 问题4 : 检测警告

eslint-disable-next-line # 忽略检测下一行  可以使用单行注释/多行注释,其他都是多行注释
eslint-disable # 忽略当前整个文件

eslint-disable no-new # 忽略前面是new开头
复制代码

六 : 项目演示

准备 :开启服务器+数据库

vue 项目学什么?

  1. 如何使用 vue 配合脚手架工具来完成一个项目
  2. 学习 ElementUI 组件库的使用
  3. 业务
  • 3.1 登录和退出
  • 3.2 用户+角色+授权+菜单
  • 3.3 商品模块

七 : 开启本地服务器

画图 : 接口访问路径 : 前端页面 ===> 接口服务器 ===> 数据库服务器 ==> 数据库

第一小步 : 打开 : 数据库服务器

打开 phpStudy ,点击启动

第二小步 : 导入数据库

  1. 打开 navicat

  2. 点击连接 : 创建一个MySQL连接

  3. 用户名和密码 : root-root(不能乱写) 这个是和 config 里的配置一样的

  4. 创建一个数据库 : shop_admin 不要乱写, 选择倒数找到 unt-8

  5. 双击打开数据库

  6. 导入 sql语句 => 右键运行 SQL 文件 => shop-api 最后一个 sql 文件

    如果没有反应 : 表 => 右键刷新

第三小步 : 开启接口服务器

  1. 打开 shop-api
  2. 运行 npm start
  3. 显示成功 : API 接口服务启动成功,占用端口 8888

第四小步 : 测试接口

http://localhost:8888/api/private/v1/login?username=admin&password=123456

项目使用接口 : (记得保存)
// shop-api里面有
复制代码

第五小步 : 使用

  • 每天做项目之前 :
    1. 每次都要先开启 phpStudy 中的 mySql
    1. 每次都要打开shop-api , 运行 npm start

八 : ES6的模块语法 (基于webpack基类演示)

8.1 : export default 默认导出一个模块 ( 简单类型 + 复杂类型 )
  • 导出 : export default

  • 默认 只能导出一个

    let str = 'abc'
    let num = 20;
    let obj = { name :'zs' }
    
    export default num
    // export default obj
    复制代码
  • 导入 : import

  • 导入的名字可以任意

  • import res from './a.js'
    console.log(res)
    复制代码
8.2 export 导出多个模块, 都放在一个对象里
  • **导出 : export **

  • // 逻辑模块 
    // 登录一个函数
    export let login = () =>  {
      console.log('登录');
    }
    // 注册一个函数
    export let register = () =>  {
      console.log('注册');
    }
    复制代码
  • 导入 : import

  • // 方式1
    import * as res from './a'
    console.log(res);
    res.login()
    res.register()
    // 方式2
    import { login, register as reg } from './a'
    login()
    register()
    复制代码
8.3 import 模块
import axios from 'axios';
复制代码

项目相关思路

一 : 初始化项目

vue init webpack shop_admin_35 清除不要的东西 (logo 和 hello world 组件 )

二 : 手动配置路由

安装 : npm i vue-router 创建一个router文件夹 / router.js 实例化路由 导出路由模块 , main.js 引入 ,挂载到vue实例上

/**

  • 准备工作

    1. 安装 npm i vue-router
    1. 引入 import VueRouter from 'vue-router'
    1. 注意点 : vue-router 和 vuex 在模块化(把他们单独提到一个js文件里)工程中,需要使用 Vue.use(安装一下)
    1. 实例化 + 挂载 (导出去再挂载)
  • 四个步骤

    1. 先把需要的组件创建出来 Login.vue Home.vue
    1. 走流程
    1. 入口 (url测试)
    1. 匹配规则
    1. 组件 (引入)
    1. 出口 */

三 : 创建两个子组件并且配置路由

1.先创建组件 /login/Login.vue 2.走流程

  1. 入口 : url手动写
  2. 规则 : {path :'/login', component: Login}
  3. 组件 : 引入即可
  4. 出口 : 在 app.vue 根组件 里 写一个出口

四 : Element-ui

链接 : element-cn.eleme.io/#/zh-CN/com… 概念 : element 是一个(基于 vue 2.X )组件库 安装 : npm i element-ui ( -S == --save == 不写 ) (-D 开发阶段需要 发布阶段不需要) 快速上手 :引入(main.js)

// 引入 element
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

// 安装一下  element-ui
Vue.use(ElementUI);
复制代码

测试 : 找到官网里的组件,拿到一个 按钮 注意点 :template 里面只能由一个根元素 one root element

五 > Login 页面 表单

el-form el-form-item

六. 发送请求 登录

  1. 接口 (本地服务器, 接口文档 )
  2. 请求工具 : axios

安装 axios 引入 使用

七 : 跳转

声明式导航 ==> 组件 标签 编程式导航 this.$router.push('/home') ==> 事件里

八 : route 和router

router : 路由实例  编程式导航(跳转)  登录拦截(导航守卫)route : 路由对象 , 包含url的信息对象, (path query, params) 解析 地址 #后面的信息

九 : 处理表单居中

注意1 : num='8' ==> 把字符串8 赋值给了num :num='8' ==> : 把 8 原来的类型赋值给num 注意2 : 如果想让label和input在一行 => 设置 label-width='100px' => el-form 如果想让 label 和 input 不在一行 =>不要设置 label-width

转载于:https://juejin.im/post/5ca2d00d6fb9a05e5f3d0315

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值