掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务
新闻动态 > 媒体报道

vue开发看这篇文章就够了(中)

组件通讯

父组件到子组件

  • 方式:通过子组件props属性来传递数据 props是一个数组
  • 注意:属性的值必须在组件中通过props属性显示指定,否则,不会生效
  • 说明:传递过来的props属性的用法与data属性的用法相同
<div id="app">
  <!-- 如果需要往子组件总传递父组件data中的数据 需要加v-bind="数据名称" -->
  <hello v-bind:msg="info"></hello>
  <!-- 如果传递的是字面量 那么直接写-->
  <hello my-msg="abc"></hello>
</div>

<!-- js -->
<script>
  new Vue({
    el: "#app",
    data : {
      info : 15
    },
    components: {
      hello: {
        // 创建props及其传递过来的属性
        props: ['msg', 'myMsg'],
        template: '<h1>这是 hello 组件,这是消息:{{msg}} --- {{myMsg}}</h1>'
      }
    }
  })
</script>

子组件到父组件

方式:父组件给子组件传递一个函数,由子组件调用这个函数

  • 说明:借助vue中的自定义事件(v-on:cunstomFn="fn")

步骤:

  • 1、在父组件中定义方法 parentFn
  • 2、在子组件 组件引入标签 中绑定自定义事件 v-on:自定义事件名="父组件中的方法" ==> @pfn="parentFn"
  • 3、子组件中通过$emit()触发自定义事件事件 this.$emit(pfn,参数列表。。。)
<hello @pfn="parentFn"></hello>

<script>
  Vue.component('hello', {
    template: '<button @click="fn">按钮</button>',
    methods: {
      // 子组件:通过$emit调用
      fn() {
        this.$emit('pfn', '这是子组件传递给父组件的数据')
      }
    }
  })
  new Vue({
    methods: {
      // 父组件:提供方法
      parentFn(data) {
        console.log('父组件:', data)
      }
    }
  })
</script>

非父子组件通讯

在简单的场景下,可以使用一个空的 Vue 实例作为事件总线
  • $on():绑定自定义事件
var bus = new Vue()

// 在组件 B 绑定自定义事件
bus.$on('id-selected', function (id) {
  // ...
})
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
  • 示例:组件A ---> 组件B
<!-- 组件A: -->
<com-a></com-a>
<!-- 组件B: -->
<com-b></com-b>

<script>
  // 中间组件
  var bus = new Vue()
  // 通信组件
  var vm = new Vue({
    el: '#app',
    components: {
      comB: {
        template: '<p>组件A告诉我:{{msg}}</p>',
        data() {
          return {
            msg: ''
          }
        },
        created() {
          // 给中间组件绑定自定义事件 注意:如果用到this 需要用箭头函数
          bus.$on('tellComB', (msg) => {
            this.msg = msg
          })
        }
      },
      comA: {
        template: '<button @click="emitFn">告诉B</button>',
        methods: {
          emitFn() {
            // 触发中间组件中的自定义事件
            bus.$emit('tellComB', '土豆土豆我是南瓜')
          }
        }
      }
    }
  })
</script>

内容分发

  • 通过<slot></slot> 标签指定内容展示区域

案例:

<!-- html代码 -->
<div id="app">
  <hello>
    <!-- 如果只有一个slot插槽 那么不需要指定名称 -->
    <p slot="插槽名称">我是额外的内容</p>
  </hello>
</div>
// js代码
new vue({
  el : "#app",
  components : {
    hello : {
      template : `
          <div>
            <p>我是子组件中的内容</p>
            <slot name="名称"></slot>
          </div>
        `
    }
  }
})

获取组件(或元素) - refs

  • 说明:vm.$refs 一个对象,持有已注册过 ref 的所有子组件(或HTML元素)
  • 使用:在 HTML元素 中,添加ref属性,然后在JS中通过vm.$refs.属性来获取
  • 注意:如果获取的是一个子组件,那么通过ref就能获取到子组件中的data和methods
<div id="app">
  <div ref="dv"></div>
  <my res="my"></my>
</div>

<!-- js -->
<script>
  new Vue({
    el : "#app",
    mounted() {
      this.$refs.dv //获取到元素
      this.$refs.my //获取到组件
    },
    components : {
      my : {
        template: `<a>sss</a>`
      }
    }
  })
</script>

SPA -单页应用程序

SPA: Single Page Application

单页Web应用(single page application,SPA),就是只有一个Web页面的应用,
是加载单个HTML页面,并在用户与应用程序交互时动态更新该页面的Web应用程序。
  • 单页面应用程序:

    • 只有第一次会加载页面, 以后的每次请求, 仅仅是获取必要的数据.然后, 由页面中js解析获取的数据, 展示在页面中
  • 传统多页面应用程序:

    • 对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面

优势

  • 1 减少了请求体积,加快页面响应速度,降低了对服务器的压力
  • 2 更好的用户体验,让用户在web app感受native app的流畅

实现思路和技术点

  • 1 ajax
  • 2 锚点的使用(window.location.hash #)
  • 3 hashchange 事件 window.addEventListener("hashchange",function () {})
  • 4 监听锚点值变化的事件,根据不同的锚点值,请求相应的数据
  • 5 原本用作页面内部进行跳转,定位并展示相应的内容

路由

  • 路由即:浏览器中的哈希值(# hash)与展示视图内容(template)之间的对应规则
  • vue中的路由是:hash 和 component的对应关系

    在 Web app 中,通过一个页面来展示和管理整个应用的功能。
    SPA往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生!
    简单来说,路由就是一套映射规则(一对一的对应规则),由开发人员制定规则。
    当URL中的哈希值(# hash)发生改变后,路由会根据制定好的规则,展示对应的视图内容

基本使用

  • 安装:npm i -S vue-router
    <div id="app">
      <!-- 5 路由入口 指定跳转到只定入口 -->
      <router-link to="/home">首页</router-link>
      <router-link to="/login">登录</router-link>
    
      <!-- 7 路由出口:用来展示匹配路由视图内容 -->
      <router-view></router-view>
    </div>
    
    <!-- 1 导入 vue.js -->
    <script src="./vue.js"></script>
    <!-- 2 导入 路由文件 -->
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
      // 3 创建两个组件
      const Home = Vue.component('home', {
        template: '<h1>这是 Home 组件</h1>'
      })
      const Login = Vue.component('login', {
        template: '<h1>这是 Login 组件</h1>'
      })
    
      // 4 创建路由对象
      const router = new VueRouter({
        routes: [
          // 路径和组件一一对应
          { path: '/home', component: Home },
          { path: '/login', component: Login }
        ]
      })
    
      var vm = new Vue({
        el: '#app',
        // 6 将路由实例挂载到vue实例
        router
      })
    </script>

重定向

//  将path 重定向到 redirect
{ path: '/', redirect: '/home' }

路由其他配置

  • 路由导航高亮

    • 说明:当前匹配的导航链接,会自动添加router-link-exact-active router-link-active类
    • 配置:linkActiveClass
  • 匹配路由模式

    • 配置:mode
new Router({
  routers:[],
  mode: "hash", //默认hash | history 可以达到隐藏地址栏hash值 | abstract,如果发现没有浏览器的 API 则强制进入
  linkActiveClass : "now" //当前匹配的导航链接将被自动添加now类
})

路由参数

  • 说明:我们经常需要把某种模式匹配到的所有路由,全都映射到同一个组件,此时,可以通过路由参数来处理
  • 语法:/user/:id
  • 使用:当匹配到一个路由时,参数值会被设置到 this.$route.params
  • 其他:可以通过 $route.query 获取到 URL 中的查询参数 等
    // 方式一
    <router-link to="/user/1001">如果你需要在模版中使用路由参数 可以这样 {{$router.params.id}}</router-link>
    // 方式二
    <router-link :to="{path:'/user',query:{name:'jack',age:18}}">用户 Rose</router-link>


    <script>
    // 路由
    var router = new Router({
      routers : [
        // 方式一 注意 只有/user/1001这种形式能被匹配 /user | /user/ | /user/1001/ 都不能被匹配
        // 将来通过$router.params获取参数返回 {id:1001}
        { path: '/user/:id', component: User }, 
        // 方式二
        { path: "user" , component: User}
      ]
    })
    
    // User组件:
    const User = {
      template: `<div>User {{ $route.params.id }}</div>`
    }
    </script>  
    <!-- 如果要子啊vue实例中获取路由参数 则使用this.$router.params 获取路由参数对象 -->
    <!--  {{$router.query}} 获取路由中的查询字符串 返回对象 -->

嵌套路由 - 子路由

  • 路由是可以嵌套的,即:路由中又包含子路由
  • 规则:父组件中包含 router-view,在路由规则中使用 children 配置
    // 父组件:
    const User = Vue.component('user', {
      template: `
        <div class="user">
          <h2>User Center</h2>
          <router-link to="/user/profile">个人资料</router-link>
          <router-link to="/user/posts">岗位</router-link>
          <!-- 子路由展示在此处 -->
          <router-view></router-view>
        </div>
        `
    })
    
    // 子组件[简写]
    const UserProfile = {
      template: '<h3>个人资料:张三</h3>'
    }
    const UserPosts = {
      template: '<h3>岗位:FE</h3>'
    }
    
    // 路由
    var router =new Router({
      routers : [

        { path: '/user', component: User,
          // 子路由配置:
          children: [
            {
              // 当 /user/profile 匹配成功,
              // UserProfile 会被渲染在 User 的 <router-view> 中
              path: 'profile',
              component: UserProfile
            },
            {
              // 当 /user/posts 匹配成功
              // UserPosts 会被渲染在 User 的 <router-view> 中
              path: 'posts',
              component: UserPosts
            }
          ]
        }
      ]
    })

前端模块化

为什么需要模块化
  • 1 最开始的js就是为了实现客户端验证以及一些简单的效果
  • 2 后来,js得到重视,应用越来越广泛,前端开发的复杂度越来越高
  • 3 旧版本的js中没有提供与模块(module)相关的内容

模块的概念

  • 在js中,一个模块就是实现特定功能的文件(js文件)
  • 遵循模块的机制,想要什么功能就加载什么模块
  • 模块化开发需要遵循规范

模块化解决的问题

  • 1 命名冲突
  • 2 文件依赖(加载文件)
  • 3 模块的复用
  • 4 统一规范和开发方式

JS实现模块化的规范

  • AMD 浏览器端

    • requirejs
  • CommonJS nodejs

    • 加载模块:require()
    • 导出模块:module.exports = {} / exports = {}
  • ES6 中的 import / export
  • CMD 浏览器端

    • 玉伯(阿里前端大神) -> seajs
  • UMD 通用模块化规范,可以兼容 AMD、CommonJS、浏览器中没有模块化规范 等这些语法

AMD 的使用

Asynchronous Module Definition:异步模块定义,浏览器端模块开发的规范 代表:require.js 特点:模块被异步加载,模块加载不影响后面语句的运行

1、定义模块

    // 语法:define(name, dependencies?, factory);
    // name表示:当前模块的名称,是一个字符串 可有可无
    // dependencies表示:当前模块的依赖项,是一个数组无论依赖一项还是多项 无则不写
    // factory表示:当前模块要完成的一些功能,是一个函数
    
    // 定义对象模块
    define({})
    // 定义方法模块
    define(function() {
      return {}
    })
    // 定义带有依赖项的模块
    define(['js/a'], function() {})

2、加载模块

// - 注意:require的第一个参数必须是数组

    // 参数必须是数组 表示模块路径 以当前文件为基准,通过回调函数中的参数获取加载模块中的变量 参数与模块按照顺序一一对应
    require(['a', 'js/b'], function(a, b) {
      // 使用模块a 和 模块b 中的代码
    })

3、路径查找配置

  • requirejs 默认使用 baseUrl+paths 的路径解析方式
  • 可以使用以下方式避开此设置:

// 配置示例
    // 注意配置应当在使用之前
    require.config({
      baseUrl: './js' // 配置基础路径为:当前目录下的js目录
    })
    require(['a'])    // 查找 基础路径下的 ./js/a.js

// 简化加载模块路径
    require.config({
      baseUrl: './js',
      // 配置一次即可,直接通过路径名称(template || jquery)加载模块
      paths: {
        template: 'assets/artTemplate/template-native',
        jquery: 'assets/jquery/jquery.min'
      }
    })
    // 加载jquery template模块
    require(['jquery', 'template'])

4、非模块化和依赖项支持

  • 1 添加模块的依赖模块,保证加载顺序(deps)
  • 2 将非模块化模块,转化为模块化(exports)
// 示例
    require.config({
      baseUrl: './js',
      paths: {
        // 配置路径
        noModule: 'assets/demo/noModule'
      },
      // 配置不符合规范的模块项
      shim: {
        // 模块名称
        noModule: {
          deps: [],         // 依赖项
          exports: 'sayHi'  // 导出模块中存在的函数或变量
        }
      }
    });

// 注意点  如果定义模块的时候,指定了模块名称,需要使用该名称来引用模块
    // 定义 这个模块名称与paths中的名称相同
    define('moduleA', function() {})
    // 导入
    require.config({
      paths: {
        // 此处的模块名:moduleA
        moduleA: 'assets/demo/moduleA'
      }
    })

5、路径加载规则

  • 路径配置的优先级:

    • 1 通过 config 配置规则查找
    • 2 通过 data-main 指定的路径查找
    • 3 以引入 requirejs 的页面所在路径为准查找
    <!-- 
      设置data-main属性
      1 data-main属性指定的文件也会同时被加载
      2 用于指定查找其他模块的基础路径
    -->
    <script src="js/require.js" data-main="js/main"></script>

Webpack

  • webpack 官网
  • bundle [ˈbʌndl] 捆绑,收集,归拢,把…塞入
1 webpack 将带有依赖项的各个模块打包处理后,变成了独立的浏览器能够识别的文件
2 webpack 合并以及解析带有依赖项的模块

概述

webpack 是一个现代 JavaScript 应用程序的模块打包器(特点 module、 bundler) 
webpack 是一个模块化方案(预编译) 
webpack获取具有依赖关系的模块,并生成表示这些模块的静态资源
  • 四个核心概念:入口(entry)输出(output)加载器loader插件(plugins)
对比
模块化方案: webpack 和 requirejs(通过编写代码的方式将前端的功能,划分成独立的模块)

browserify 是与 webpack 相似的模块化打包工具

webpack 预编译 (在开发阶段通过webpack进行模块化处理, 最终项目上线, 就不在依赖于 webpack)
requirejs 线上的编译( 代码运行是需要依赖与 requirejs 的 )

webpack起源

  • webpack解决了现存模块打包器的两个痛点:

    • Code Spliting - 代码分离 按需加载
    • 静态资源的模块化处理方案

webpack与模块

  • 前端模块系统的演进
  • 在webpack看来:所有的静态资源都是模块
  • webpack 模块能够识别以下等形式的模块之间的依赖:
  • JS的模块化规范:

    • ES2015 import export
    • CommonJS require() module.exports
    • AMD define 和 require
  • 非JS等静态资源:

    • css/sass/less 文件中的 @import
    • 图片连接,比如:样式 url(...) 或 HTML <img src=...>
    • 字体 等

webpack文档和资源


安装webpack

  • 全局安装:npm i -g webpack

    • 目的:在任何目录中通过CLI使用 webpack 这个命令
  • 项目安装:npm i -D webpack

    • 目的:执行当前项目的构建

webpack的基本使用

  • 安装:npm i -D webpack
  • webpack的两种使用方式:1 命令行 2 配置文件(webpack.config.js)

命令行方式演示 - 案例:隔行变色

  • 1 使用npm init -y 初始package.json,使用npm来管理项目中的包
  • 2 新建index.html和index.js,实现隔行变色功能
  • 3 运行webpack src/js/index.js dist/bundle.js进行打包构建,语法是:webpack 入口文件 输出文件
  • 4 注意:需要在页面中引入 输出文件 的路径(此步骤可通过配置webpack去掉)
/*
  src/js/index.js
*/

// 1 导入 jQuery
import $ from 'jquery'
// 2 获取页面中的li元素
const $lis = $('#ulList').find('li')
// 3 隔行变色
// jQuery中的 filter() 方法用来过滤jquery对象
$lis.filter(':odd').css('background-color', '#def')
$lis.filter(':even').css('background-color', 'skyblue')

//命令行运行 `webpack src/js/index.js   dist/bundle.js   目录生成在命令行运行目录
/*
  运行流程:
  1、webpack 根据入口找到入口文件
  2、分析js中的模块化语法 
  3、将所有关联文件 打包合并输出到出口
*/

webpack-dev-server 配置

一、package.json配置方式

  • 安装:npm i -D webpack-dev-server
  • 作用:配合webpack,创建开发环境(启动服务器、监视文件变化、自动编译、刷新浏览器等),提高开发效率
  • 注意:无法直接在终端中执行 webpack-dev-server,需要通过 package.json 的 scripts 实现
  • 使用方式:npm run dev
// 参数解释  注意参数是无序的 有值的参数空格隔开
// --open 自动打开浏览器
// --contentBase ./  指定浏览器 默认打开的页面路径中的 index.html 文件
// --open 自动打开浏览器
// --port 8080 端口号
// --hot 热更新,只加载修改的文件(按需加载修改的内容),而非全部加载
"scripts": {
  "dev": "webpack-dev-server --open --contentBase ./ --port 8080 --hot"
}

二、webpack.config.js 配置方式(推荐)

var path = require('path')
module.exports = {
  // 入口文件
  entry: path.join(__dirname, 'src/js/index.js'),

  // 输出文件
  output: {
    path: path.join(__dirname, 'dist'),   // 输出文件的路径
    filename: 'bundle.js'                 // 输出文件的名称
  }
}

const webpack = require('webpack')

devServer: {
  // 服务器的根目录 Tell the server where to serve content from
  // https://webpack.js.org/configuration/dev-server/#devserver-contentbase
  contentBase: path.join(__dirname, './'),
  // 自动打开浏览器
  open: true,
  // 端口号
  port: 8888,

  // --------------- 1 热更新 -----------------
  hot: true
},

plugins: [
  // ---------------- 2 启用热更新插件 ----------------
  new webpack.HotModuleReplacementPlugin()
]
  • html-webpack-plugin 插件

    • 安装:npm i -D html-webpack-plugin
    • 作用:根据模板,自动生成html页面
    • 优势:页面存储在内存中,自动引入bundle.js、css等文件
/* webpack.config.js */
const htmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
  new htmlWebpackPlugin({
    // 模板页面路径
    template: path.join(__dirname, './index.html'),
    // 在内存中生成页面路径,默认值为:index.html
    filename: 'index.html'
  })
]

vue开发看这篇文章就够了(上)

vue开发看这篇文章就够了(下)

原文来自:segmentfault

标签/Tag

合作伙伴/Partner

提供优质服务资源的开发者服务平台