zoukankan      html  css  js  c++  java
  • vue学习之组件

    组件从注册方式分为全局组件和局部组件。

    从功能类型又可以分为偏视图表现的(presentational)和偏逻辑的(动态生成dom),推荐在前者中使用模板,在后者中使用 JSX 或渲染函数动态生成组件模板内容,整体来说表现类的组件远远多于逻辑类组件。

    定义组件

    注意:组件名最好使用全小写加短横线,即使用 kebab-case (短横线分隔命名) 定义一个组件,在引用这个自定义元素时必须使用 kebab-case,

    当使用 PascalCase (首字母大写命名) 定义一个组件时,在引用这个自定义元素时两种命名法都可以使用。

    Vue.component('MyComponentName', { /* ... */ })

    也就是说 <my-component-name><MyComponentName> 都是可接受的。

    全局组件

    Vue.component,在new根实例之前定义全局组件

    // 定义一个名为 button-counter 的全局组件
    Vue.component('button-counter', {
      data: function () {
        return {
          count: 0
        }
      },
      template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
    })
    
    //使用:
    <button-counter></button-counter>

    显示如图:

    局部组件

    全局注册的组件,对于不再使用的,仍会被包含在最终的构建结果中,造成了用户下载的 JavaScript 的增加。

    局部组件有几种注册形式,这里介绍单文件组件。

    一个单文件组件即一个vue文件,包含template(必须有),script,style三部分。

    JavaScript、CSS 分离成独立的文件然后做到热重载和预编译。

    <!-- my-component.vue -->
    <template>
      <div>This will be pre-compiled</div>
    </template>
    <script src="./my-component.js"></script>
    <style src="./my-component.css"></style>

    每个组件必须有且只有一个根元素,使用组件时,组件上的特性也会被添加到根元素上,根元素上已有的同名特性会被覆盖,除了class和style,会与组件的class和style合并,详细见下面“引用第三方库”

    //com.vue
    <template lang="html"> <div>//只能有一个html标签包裹里面所有节点    child component{{name}}
    </div> </template> <script> export default{    
        data(){//data部分必须是个函数,返回一个对象。当前组件可以使用data里面的数据
          return {
           name:'com'
           }
        }
      }
    </script>
    <style lang="css">
    </style>

     引入单文件组件

    //App.vue引入组件
    import HelloWorld from "./components/HelloWorld";
    //在页面实例注入组件
     components: {
        HelloWorld
      },
    //在页面使用组件
    <HelloWorld />
    //或者
    <HelloWorld><HelloWorld />

    组件的定义方法,参考边界处理之模板定义的替代品

    关于template标签。

    组件的复用

    每用一次组件,就会有一个它的新实例被创建,每个组件都会各自独立维护自身属性,互相独立不干扰,这也是为什么组件的data是一个函数的原因:

    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>

    父子组件

    上面例子中,App.vue的components上挂载了HelloWorld这个组件,其中App.vue是父组件,HelloWorld是子组件。

    父子组件通信

    props(参考博文):父组件传递消息给子组件,为单向的,意味着应该在一个子组件内部改变 prop。

    每次父组件发生更新时,子组件中所有的 prop 都将会刷新为最新的。

    //子组件中声明props
    <template lang="html">
       <div>
        年龄:{{age}}
        </div>
    </template>
    <script>
        export default{
          props:['age'],
          data(){
            return{
              name:'com'
            }
          }
        }
    </script>
    
    //组件特性传入prop值
     <com age="19"></com>//静态数据
     <com :age="ageNum"></com>//动态数据:变量

    两种常见的试图改变一个 prop 的情形

    1、这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值

    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }

    2、这个 prop 以一种原始的值传入且需要对这个值进行操作在这种情况下,最好使用这个 prop 的值来定义一个计算属性

    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }

    注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。

    $emit:子组件向父组件传递数据

    使用.sync修饰符双向绑定父子组件的变量

    比如下面,点击子组件的这个按钮(子组件接收的用户行为),触发组件自定义的patch事件,执行patch事件的处理函数msg3,改变父组件的ageNum数据

    在子组件中代码:

    <button type="button" name="button" @click="$emit('patch',[参数])">发送到父组件</button>

    父组件中代码:

    <com :age="ageNum" @patch='msg3'></com>//动态数据:变量
    export default{
        data(){
          return {
            ageNum: 18
          }
        },

    methods: {
      msg3(params){
         //params:子组件传递过来的参数 
        this.ageNum++
      }
     }
    }

    vm.$attrs 属性和vm.$listeners属性(单向传值,查阅博文:实例属性和方法

    常用在跨级组件中,祖孙组件通信。

    组件上使用v-model指令

    查阅博文:v-model

    组件上的原生事件

    在一个组件的根元素上直接监听一个原生事件,使用 v-on.native 修饰符。

    <base-input v-on:focus.native="onFocus"></base-input>

    插槽和作用域插槽

    查阅博文:slot

    引用第三方库的组件

    组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上。

    例如,你通过一个 Bootstrap 插件使用了一个第三方的 <bootstrap-date-input> 组件,然后这个 data-date-picker="activated" 特性就会自动添加到 <bootstrap-date-input> 这个组件的根元素上:

    <bootstrap-date-input
      data-date-picker="activated"
      class="date-picker-theme-dark"
    ></bootstrap-date-input>

    该组件根元素为

    <input type="date" class="form-control">

    替换/合并根元素已有特性

    对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值。所以如果组件上有 type="text" ,input的 type="date" 就会被替换掉并被破坏!classstyle 特性会把两边的值会被合并起来,最终的值:form-control date-picker-theme-dark

    最终,input为:

    <input
    type="date"
    data-date-picker="activated"
      class="form-control date-picker-theme-dark
    ">

    禁用特性继承

    如果你希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false,该选项不会影响 styleclass 的绑定。适合配合实例的 $attrs 属性使用。

    组件嵌套在有嵌套规则的标签里

    有些 HTML 元素,诸如 <ul><ol><table><select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li><tr><option>,只能出现在其它某些特定的元素内部。

    //这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部
    <table>
      <blog-post-row></blog-post-row>
    </table>

    通过is特性解决:

    <table>
      <tr is="blog-post-row"></tr>
    </table>

    动态组件

    使用vue内置标签<component>,通过添加is特性来切换不同的组件。

    比如:在一个多标签的界面中切换不同的组件(这个标签的位置渲染为那个组件)

    <!-- 组件会在 `currentTabComponent` 改变时改变 -->
    <component v-bind:is="currentTabComponent"></component>

    在上述示例中,currentTabComponent 可以是

    • 已注册组件的名字
    • 一个组件的选项对象(推荐)

    当想保持组件被切换时的状态,以避免反复重渲染导致的性能问题。

    比如下例,posts的第二个文章被选中,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示之前选择的文章的。

    需求:组件实例能够在它们第一次被创建的时候缓存下来。

    方案:<keep-alive> 元素将动态组件包裹起来。

    参考博文:vue内置标签

    异步组件

    在需要的时候才从服务器加载一个模块,Vue 提供一个工厂函数,resolve 回调会在从服务器得到组件定义的时候被调用。

    Vue.component('async-example', function (resolve, reject) {
      setTimeout(function () {//setTimeout 是为了演示用的,如何获取组件取决于业务。
        // 向 `resolve` 回调传递组件定义
        resolve({
          template: '<div>I am async!</div>'
        })
      }, 1000)
    })

    一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用:

    Vue.component('async-webpack-example', function (resolve) {
      // 这个特殊的 `require` 语法将会告诉 webpack
      // 自动将你的构建代码切割成多个包,这些包
      // 会通过 Ajax 请求加载
      require(['./my-async-component'], resolve)
    })

    也可以在工厂函数中返回一个 Promise:

    Vue.component(
      'async-webpack-example',
      // 这个 `import` 函数会返回一个 `Promise` 对象。
      () => import('./my-async-component')
    )

    当使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:

    new Vue({
      // ...
      components: {
        'my-component': () => import('./my-async-component')
      }
    })

    处理加载状态:

    const AsyncComponent = () => ({
      // 需要加载的组件 (应该是一个 `Promise` 对象)
      component: import('./MyComponent.vue'),
      // 异步组件加载时使用的组件
      loading: LoadingComponent,
      // 加载失败时使用的组件
      error: ErrorComponent,
      // 展示加载时组件的延时时间。默认值是 200 (毫秒)
      delay: 200,
      // 如果提供了超时时间且组件加载也超时了,
      // 则使用加载失败时使用的组件。默认值是:`Infinity`
      timeout: 3000
    })

    Vue Router 的路由组件中使用上述语法的话,必须使用 Vue Router 2.4.0+ 版本。

    组件值之处理边界情况

    介绍组件使用中遇到的一些问题:父子孙组件的访问,组件循环或者互相引用,模板其他的定义方式,强制更新(数组对象的变更检测注意事项,或者可能依赖了非响应式状态),在根元素使用v-once创建静态组件。

    基础组件一次性引入

    推荐创建一个 components 目录管理单文件组件。

    针对基础组件的长列表的改善:

    import BaseButton from './BaseButton.vue'
    import BaseIcon from './BaseIcon.vue'
    import BaseInput from './BaseInput.vue'
    
    export default {
      components: {
        BaseButton,
        BaseIcon,
        BaseInput
      }
    }

    使用webpack(或在内部使用了 webpack 的 Vue CLI 3+)的前提下,使用 require.context 全局注册这些基础组件。

    以下代码放在应用入口文件 (比如 src/main.js) 中全局导入基础组件

    import Vue from 'vue'
    import upperFirst from 'lodash/upperFirst'
    import camelCase from 'lodash/camelCase'
    
    const requireComponent = require.context(
      // 其组件目录的相对路径
      './components',
      // 是否查询其子目录
      false,
      // 匹配基础组件文件名的正则表达式
      /Base[A-Z]w+.(vue|js)$/
    )
    
    requireComponent.keys().forEach(fileName => {
      // 获取组件配置
      const componentConfig = requireComponent(fileName)
    
      // 获取组件的 PascalCase 命名
      const componentName = upperFirst(
        camelCase(
          // 剥去文件名开头的 `./` 和结尾的扩展名
          fileName.replace(/^./(.*).w+$/, '$1')
        )
      )
    
      // 全局注册组件
      Vue.component(
        componentName,
        // 如果这个组件选项是通过 `export default` 导出的,
        // 那么就会优先使用 `.default`,
        // 否则回退到使用模块的根。
        componentConfig.default || componentConfig
      )
    })
  • 相关阅读:
    在CHROME里安装 VIMIUM 插件, 方便操作
    Python 判断变量的类型
    Python 格式化输出
    ssh 使用
    [转载] 构造linux 系统下免密码ssh登陆  _How to establish password-less login with SSH
    [转载] SSH入门学习基础教程
    SSH 常用命令解析
    【转载】 调研文献的方法介绍,适用于各个领域
    POJ 2549 Sumsets
    HDU 5858 Hard problem
  • 原文地址:https://www.cnblogs.com/yaoyao-sun/p/10363246.html
Copyright © 2011-2022 走看看