• vue2.X心得


    VUEJS学习网址:https://cn.vuejs.org/

    此文章是用来记录自己的学习和实践心得。

    关注点:父子组件之间的通信

    看图说话:

    Pass Props

    • 子组件本身与父组件是孤立的,通过子组件中显示声明的props属性,接收父组件数据;
    • 父组件的数据更新时,子组件的prop会跟着更新;
    • 此数据流动是单向的(看着);

    Emit Events

    • 子组件使用$.emit(fn)向外抛出自己的内部触发的事件;
    • 父组件是否监听?如果父组件需要监听,使用v-on绑定监听,触发对应事件;

    以上为通用语,具体分析

    • 子组件可以接收一个字符串,在子组件内部可以用{{label}}使用 
    <v-input label="姓名"></v-input>
    • 子组件可以接收动态参数
    <input v-model="msg" />
    <v-profile :message="msg"></v-profile>

    子组件接收到数据之后想处理一下不小心改了怎么办?

    • 给prop创建一个副本(建议深拷贝),处理副本,不动prop;

    父组件的数据改变后,子组件的prop会自动更新,但是这个prop的副本不会啊?

    • 使用watch监听这个prop,改变时更新副本;

    子组件的prop副本改变了想要通知父组件怎么办?

    • 使用watch监听这个副本,改变时向外抛出自己的内部触发的事件;

    (添加)父组件的prop改变,但是不想通知子组件怎么办?

    • 使用.once显式指定单次绑定

    。。。

    其实以上???在2.3有了更好的方法,之前的就是看看。

    .sync修饰符

    ***父组件***
    <input v-model="msg" />
    <v-profile :message.sync="msg"></v-profile>
    ***子组件***
    $.emit('update:message',newValue)

    (9-21)补充:注释还是建议使用data或compute属性,而不是直接修改prop

    子组件想要触发父组件可以emit(父组件需要监听才会触发),父组件触发子组件事件呢?

    • 通过在引用的子组件上使用ref属性实现父组件调用子组件的方法以及属性

    但是$refs 只在组件渲染完成后才填充,并且它是非响应式的。它仅仅作为一个直接访问子组件的应急方案——应当避免在模版或计算属性中使用 $refs 。

    关注点:非父子组件之间的通信

     使用空的vue实例作为中央事件总线

    var bus = new Vue();
    // 触发组件 A 中的事件
    bus.$emit('id-selected', 1)
    
    
    // 在组件 B 创建的钩子中监听事件
    bus.$on('id-selected', function (id) {
      // ...
    })

    考虑vuex

    (2018-07-28)注意到了$attrs和¥listeners,用于在多层嵌套中交互,见文档

    关注点:在组件中使用slot

    首先,在父组件中给子组件标签中间放置内容是无效的。然后slot出场。

    白话版本:

    匿名slot:
        slot标签存在与子组件template中;
        子组件在父组件中使用的时候,子组件标签中的结构会在编译后替换子组件的slot标签;
    如果子组件中没有slot,则父组件中子组件标签中的内容会消失; 具名slot: 顾名思义,是具有name属性的slot标签;并有匿名组件的特性(以上); 子组件在父组件中使用的时候,子组件中的结构中会有某些标签拥有slot属性并赋值,这些会在编译后替换子组件的相应slot标签;

    一句话解释:主要的内容是写在父组件中的子组件标签中,编译后插入子组件的相应位置

    讲真,说到这里我自己都不明白要slot干嘛。

    官方讲解入口

    官方给了个布局的例子:

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    View Code
    <app-layout>
      <h1 slot="header">这里可能是一个页面标题</h1>
      <p>主要内容的一个段落。</p>
      <p>另一个主要段落。</p>
      <p slot="footer">这里有一些联系信息</p>
    </app-layout>
    View Code

    但是好像也没什么好推荐的。(个人看法)

    再想想:

    子组件的template中至少有一个slot标签,slot标签中的内容是default content。什么场景能用到呢?我想到了刚刚写的表格数据筛选,当时用的是v-if,v-else。如果改成slot呢。。。想到slot属性值需要动态传餐,原来写在子组件内部的过滤过程要搬出来放到父组件中执行,然后把执行好的数据塞给子组件的prop。。。

    再理一次:

    我在子组件的template中设置两个slot

    <slot name="Data">各种展现数据的结构都放这里</slot>
    <slot name="noData">没有相关数据</slot>

    父组件中设置

    <input v-model="filterData" />
    <button v-on:click="filterMethod">筛选</button>
    <v-table :datas="datas">
        <div slot="Data">
        ...
      <div> <v-tabel>

    关键就是slot属性动态赋值的问题。。。走不通,脑洞大了按下不说了

    作用域插槽

    语法:

    <template scope="props">
      ...
    </template>

     ——————这个官网例子我是好半天才明白

    <my-awesome-list :items="items">
      <!-- 作用域插槽也可以是具名的 -->
      <template slot="item" scope="props">
        <li class="my-fancy-item">{{ props.text }}</li>
      </template>
    </my-awesome-list>

    以上的template中的props其实和子组件的props属性是相同的,子组件传递了什么prop,它就接收什么,像是下边的传了个text

    <ul>
      <slot name="item"
        v-for="item in items"
        :text="item.text">
        <!-- 这里写入备用内容 -->
      </slot>
    </ul>

    我看了很长很长时间,为什么要这么拐个弯呢。。。

    ————一夜过后—————

    这样内容更灵活:数据是相同的(父组件提供数据),子组件负责了循环(添加逻辑),父组件引用子组件时插入的作用域插槽的模板决定了(展示的形式)!这分工!!!点个赞!!!

    我修改了一下自己的table然后页面展示了个空白。之后发现问题出在子组件往外传数据的时候变量名不能用"name"。修改掉。2017-07-14:使用index也不行。。。

    2017-07-15:在实际使用的时候发现复用性不强。感觉父子组件之间声明式props传递数据的方式使增强复用性变得困难。

    关注点:动态组件使用

    • 通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,我们让多个组件可以使用同一个挂载点,并动态切换:很适用于制作Tab类的效果
    <component v-bind:is="currentView" :data1="data1" :data2="data2">
      <!-- 组件在 vm.currentview 变化时改变! -->
    </component>
    • 在methods属性中定义一个函数修改currentView即可。
    • 视情况可以配合 keep-alive 避免重新渲染
    • 在子组件上放置activated钩子做切换时的工作:done() //放到钩子最后,表示执行工作完毕,可以切换组件,配合keep-alive使用,activated钩子只执行一次
    • 子组件接收数据和以往相同,只是这一次都写在了component中,只是如此的话,每个子组件都需要有这些接口(prop)

    暂时说到这里,突然得回头看一下react,没时间了,回头会继续。

    以上的满基础的(我是新手),有什么不对的求指出,感谢!!!

    添加:

    关注点:组件间的循环引用

    使用全局注册的时候没有问题(框架自行解决)

    如果是模块引用(我都是这样的),需要在第一次循环的子组件上声明

    beforeCreate: function () {
      this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue')
    }

    自己模仿的示例

    treeFolder

    <template>
    <ul>
    <li v-for="folder in folders">
    <span @click="toggle(folder)">folder.name:{{folder.name}}</span>
    <tree-folder-content v-if="folder.children"
    :children="folder.children"
    v-show="folder.show"
    />
    </li>
    </ul>
    </template>
    <script>
    import treeFolderContent from './treeFolderContent.vue';
    export default{
    name: "tree-folder",
    data(){
    return {
    expand: false
    }
    },
    components: {
    'tree-folder-content': treeFolderContent
    },
    props: ['folders'],
    methods:{
    toggle: function(item) {
    item.show = !item.show;
    }
    }
    }
    </script>

     treeFolderContent

    <template>
    <ul>
    <li v-for="child in children">
    <span @click="toggle(child)">child.name:{{child.name}}</span>
    <TreeFolder v-if="child.children"
    :folders="child.children"
    v-show="child.show"
    />
    </li>
    </ul>
    </template>
    <script>
    export default{
    name: "tree-folder-content",
    beforeCreate(){
    this.$options.components.TreeFolder = require('./treeFolder.vue');
    },
    data(){
    return {
    expand: false
    }
    },
    props: ['children'],
    methods:{
    toggle: function(item) {
    item.show = !item.show;
    }
    }
    }
    </script>

    引用方式

    <template>
    <div class="main">
    <div class="content">
    <tree-folder :folders="menu"></tree-folder>
    </div>
    </div>
    </template>
    <script>
    import treeFolder from './../commen/treeFolder.vue'
    export default{
    name: "nav3",
    data(){
    return {
    menu: [
    {
    name: 'a一级导航', show: true,
    children: [
    {name: 'a二级导航', show: false},
    {name: 'a二级导航', show: false}
    ]
    },
    {
    name: 'b一级导航', show: true,
    children: [
    {name: 'b二级导航', show: false},
    {name: 'b二级导航', show: false},
    {
    name: 'b二级导航', show: false,
    children: [
    {
    name: 'b三级导航', show: false,
    children: [
    {name: 'b四级导航', show: false,}
    ]
    }
    ]
    },
    ]
    },
    {
    name: 'c一级导航', show: true,
    children: [
    {name: 'c二级导航', show: false},
    {name: 'c二级导航', show: false},
    {
    name: 'c二级导航', show: false,
    children: [
    {name: 'c三级导航', show: false}
    ]
    },
    ]
    }
    ]
    }
    },
    components: {
    'tree-folder': treeFolder
    }
    }
    </script>
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="less" rel="stylesheet/less">
    .content {
    background: blue;
    color: #fff;
    }
    </style>

     

    小点tip:

    • 低开销的静态组件使用v-once(2017-07-15修改,之前误写成v-on):尽管在 Vue 中渲染 HTML 很快,不过当组件中包含大量静态内容时,可以考虑使用 v-once将渲染结果缓存起来;

     关注点:关于过滤器

    vue1.x版本中有很多系统自带的过滤器,在vue2.x版本中都没有了。

    • 对于删除掉的那些过滤器可以使用Vue.filter()在全局注册自定义相同功能。必须放在Vue实例化前面。
    • 或是使用filters在示例内部注册
    • 或是使用Array的新语法filter和computed属性先处理数据返回新的data

    2017-07-15

    关注点:组件生命周期

     

    看图说话:

      1. beforeCreated:声明------创建实例,但是实例并未创建的阶段,这时候关于Vue实例的属性和方法等都还没有读取到。这是Vuejs实例周期中的第一个阶段,在DOM展示出来(mounted)还有一段时间,我们可以在这里添加loading,增加用户体验。例如:document.body.appendChild(loading);
      2. created:实例已经创建好了,读到了data(observe data)和自带的事件(Init Event),此时在钩子中运行console.log(this)查看输出。这时候我们可以做一些异步请求,例如请求一些服务器上的数据等。
      3. 这个Vue实例有el属性吗?如果没有,使用.$mounted("#app")使组件在mounted阶段挂载到#app下;如果有,直接在mounted阶段挂载到#app下;
      4. 这个Vue实例有template吗?如果有,把template编译成render函数(render函数构造虚拟DOM);如果没有,将el的outerHTML(包括el本身)当做template编译成render函数;
      5. beforeMounted:不知道这时候干什么好
      6. mounted:此时,使用vue生成的DOM结构将代替el,可以操作新的#app的DOM结构了,此时,在beforeCreated阶段添加的loading可以消失了;(在这里,我最开始写的是document.body.removeChild(loading);然而并没有什么用,只能给loading加上类名重新选定删除,以下是loading代码。如果是我JS不精造成的问题,请指出!!!):::::::::::20180430:注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted。OK,问题解决。
      7. DOM展现给用户后,用户操作(v-on)引发data change。但是这时候并不是直接操作DOM,而是操作虚拟dom(个人理解:由vue-loader将vue组件文件中的代码解析成了javascript,(render的过程)在用户操作的时候,最先操作这些伪DOM(js操作),然后在re-render成真正的DOM。再此,也总结出vue的一大特点:data和dom并不是直接通讯,而是通过虚拟dom)。这里又牵扯出了数据驱动。。。看图。。。先看看,等等换成新的关注点吧(>.<)

      8. beforeUpdata:数据已更新,但是虚拟 DOM 重新渲染和打补丁之前触发,此时还可以对data进行操作,此时的data修改并不会触发重渲染(完成你的自定义操作一起渲染)。官网上有一句:该钩子在服务器端渲染期间不被调用。没有接触服务器端渲染,不谈。
      9. re-render
      10. updated:此时DOM已经更新了(mounted)

        当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。(官网原文,我觉得记着就好)

        该钩子在服务器端渲染期间不被调用。

      11. 如果调用了vm.$destroy()(将new Vue({})赋值给变量vm),会先触发beforeDestroy钩子,此时,还是可以操作实例;destroyed钩子紧接着被调用。。。就将所有的watcher,components,listeners删除(此时请再看一眼数据驱动原理图)。之后我又console.log(vm),在控制台上还是能够访问到这个实例Vue$3(怎么命名的啊),换言之,这个实例只是回到了beforeCreated阶段。已经渲染出来的DOM,如果依赖data和init event则会消失,不依赖的会留下。
    //用Javascript代码表示DOM节点的伪代码
    Let domNode = {
      tag: 'ul'
      attributes: { id: 'myId' }
      children: [
    //这里是 li
      ]
    };
    var loading = document.createElement("div");
    loading.style.width = "1000px";
    loading.style.height = "1000px";
    loading.className = 'loading';
    loading.style.backgroundColor = "#000";

    数据驱动原理

    关注点:表格展示示例

    链接:

    2017-07-17

    关注点:动画

    会有 6 个(CSS)类名在 enter/leave 的过渡中切换

    1. v-enter: 定义进入过渡的开始状态。在元素被插入时生效,在下一个帧移除。

    2. v-enter-active: 定义过渡的状态。在元素整个过渡过程中作用,在元素被插入时生效,在 transition/animation 完成之后移除。 这个类可以被用来定义过渡的过程时间,延迟和曲线函数。

    3. v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入一帧后生效(于此同时 v-enter 被删除),在 transition/animation 完成之后移除。

    4. v-leave: 定义离开过渡的开始状态。在离开过渡被触发时生效,在下一个帧移除。

    5. v-leave-active: 定义过渡的状态。在元素整个过渡过程中作用,在离开过渡被触发后立即生效,在 transition/animation 完成之后移除。 这个类可以被用来定义过渡的过程时间,延迟和曲线函数。

    6. v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发一帧后生效(于此同时 v-leave 被删除),在 transition/animation 完成之后移除。

    看概念并不难,直接说我跳过的坑:

    css过渡

    • 如果设置了v-enter-to,过渡的是v-enter到v-enter-to,如果没有,就是v-enter到你加入动画之前的最初样式,同理v-leave-to
    • 自定类名的时候可以使用name属性重置v前缀 

    css动画 顾名思义,是动画 animation 。

    搭配animate.css一起使用。可以通过以下特性来自定义过渡类名:他们的优先级高于普通的类名

    • enter-class
    • enter-active-class
    • enter-to-class (>= 2.1.8 only)
    • leave-class
    • leave-active-class
    • leave-to-class (>= 2.1.8 only)

    关注点:方法事件处理器 methods

    • 在内联方法中传入特殊变量$event,可以在methods中定义的该方法中访问原生事件对象。
    • 在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。(原文)
    <button v-on:click="warn(' ...', $event)">
      Submit
    </button>
    ......
    methods: {
      warn: function (message, event) {
        // 现在我们可以访问原生事件对象
        if (event) event.preventDefault()
        alert(message)
      }
    }

    关注点:事件修饰符

    <!-- 阻止单击事件冒泡 -->
    <a v-on:click.stop="doThis"></a>
    <!-- 阻止默认事件 -->
    <form v-on:submit.prevent="onSubmit"></form>
    <!-- 点击事件将只会触发一次 -->
    <a v-on:click.once="doThis"></a>
    
    <!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
    <input v-on:keyup.13="submit">
    <!-- 同上 -->
    <input v-on:keyup.enter="submit">
    <!-- 缩写语法 -->
    <input @keyup.enter="submit">
    
    .enter
    .tab
    .delete (捕获 “删除” 和 “退格” 键)
    .esc
    .space
    .up
    .down
    .left
    .right
    
    自定义键值修饰符
    Vue.config.keyCodes.f1 = 112

    鼠标或键盘事件监听

    .ctrl
    .alt
    .shift
    .meta

    关注点:命名视图

    https://jsfiddle.net/posva/6du90epg/

    关注点:v-once 与 keep-alive

    今天把自己写的心得又读了一遍,对v-once 和keep-alive有点迷惑

    v-once只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

    keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

    今天11月30日,因为一些原因我有2个月没有注意“vuejs”,就这样它悄悄地改变了。。。

    纸上得来终觉浅,希望有机会去实践。

    实践来了。

    2018.1.15

    工作告一个段落了,使用公司的接口将新的webApp项目改成了vuejs项目。不是每个页面都重新写了,时间也是不允许的吧。

    实现:vue-router,vuex,vue-resourse,selected,下拉加载,输入框和select等。

    地址:*********************老大说放公司代码属于侵权。。。

    不会再新增关于vue的新随笔,就这一篇,不断的补充,感觉也挺好。(我又加了一个关于框架的。。。)

    关注点:watch

    watch用来监控某个变化的属性,然后执行方法。在我以往的使用中,只有该监控的属性发生变化时才会触发方法。

    • 若果想要初始时就执行这个方法,需要传入新的属性immediate,而之前的方法写到handler中,语法格式如watch: { XXXX: { handler(arg1,arg2,...) { ...},immediate: Bealoon} }。
    • 若想监控到对象某个属性的变化(Vue 不能检测到对象属性的添加或删除),以往我是直接给整个对象重新赋值,但是实际上可以通过watcher的deep属性做深层监控,语法同上一条,deep取值为Bealoon。
    • watch请尽量写在使用的组件中,监听对象也是组件内有效的,而不是在全局声明一个watch---这样你可能在不想触发的时候触发它。

     2018-08-01  在项目中使用vue有半年了,这半年来项目不断,也算是用vue‘摸爬滚打’了,但是总觉得浅。想的用的都很表面,只是‘能跑通’罢了。挫败。

  • 相关阅读:
    【原创】大叔经验分享(53)kudu报错unable to find SASL plugin: PLAIN
    【原创】大叔经验分享(52)ClouderaManager修改配置报错
    【原创】大数据基础之Impala(3)部分调优
    【原创】大数据基础之Kudu(3)primary key
    【原创】大叔经验分享(51)docker报错Exited (137)
    【原创】大数据基础之Logstash(5)监控
    【原创】大数据基础之Logstash(4)高可用
    【原创】Linux基础之vi&vim基础篇
    【原创】大叔经验分享(50)hue访问mysql(librdbms)
    【原创】大叔经验分享(49)hue访问hdfs报错/hue访问oozie editor页面卡住
  • 原文地址:https://www.cnblogs.com/Merrys/p/7112625.html
Copyright © 2020-2023  润新知