zoukankan      html  css  js  c++  java
  • 通俗易懂--快速入门Vue--3

    1.组件使用的细节点1

    • is属性在tbody中应用
    <div id="root">
        <table>
            <tbody>
                <row></row>
                <row></row>
                <row></row>
            </tbody>
        </table>
    </div>
    <script>
        Vue.component('row',{
            template:`<tr><td>this is a row</td></tr>`
        });
    
    
        var vm = new Vue({
            // el限制一个vue实例的管理范围。
            el:"#root",
        });
    
    </script>
    
    • 看似上面代码书写没有什么问题,但是打开页面你会看到,如下图:

      所有的tr标签都跑到了tbody外面,这是不符合规范的。

    • 那么如何解决这个问题,通过is属性,只需要在原来代码改一下:

      <div id="root">
          <table>
              <tbody>
                  <tr is="row"></tr>
                  <tr is="row"></tr>
                  <tr is="row"></tr>
              </tbody>
          </table>
      </div>
      

      原有的html实例不变,这样就可以避免tr标签上升到tbody标签外头了。

    • 同样像ul(li),select(option)

      <ul>
      	<li is="row"></li>
      	<li is="row"></li>
      	<li is="row"></li>
      </ul>
      
      <select>
          <option is="row"></option>
          <option is="row"></option>
          <option is="row"></option>
      </select>
      

    2.组件使用的细节点2

    • data在子组件中,必须为一个函数,同时函数有返回数据。

      Vue.component('row',{
              data:function(){
                  return {
                      content:"this is content"
                  }
              },
              template:`<tr><td>{{content}}</td></tr>`
          });
      

    3.在Vue中操作DOM

    • Vue不建议在代码中操作DOM,但是在复杂动画效果,不操作DOM,光靠数据的绑定,是无法实现的。

      <div id="app">
          <div ref="hw" @click="handleClick">hello world</div>
      </div>
      var app = new Vue({
              el:"#app",
              methods:{
                  handleClick:function () {
                      //指的是ref="hw"的DOM
                      divDom = this.$refs.hw;
                      console.log(divDom.innerHTML)
                  }
              }
          })
      
    • 那么在组件中是如何应用ref,咱们定义一个计数功能:

      <div id="root">
          <!-- 父组件监听change变化并交给 handleChange处理-->
          <counter @change="handleChange" ref="one"></counter>
          <counter @change="handleChange" ref="two"></counter>
          <div>{{total}}</div>
      </div>
      
      Vue.component("counter",{
          template:`<div @click="handleClick">{{number}}</div>`,
          data:function () {
              return {
                  number:0
              }
          },
          methods:{
              handleClick:function () {
                  this.number ++;
                  //子组件需要向父组件传递事件,当当前组件数据发生变化时。
                  this.$emit('change')
              }
          }
      });
      
      var vm = new Vue({
          // el限制一个vue实例的管理范围。
          el:"#root",
          //total用来计算两个counter组件内数据的和
          data:{
              total:0
          },
          methods:{
              handleChange:function () {
                  //total求和
                  this.total = this.$refs.one.number + this.$refs.two.number
              }
          }
      });
      

    4.父子组件的数据传递

    • 父组件可以向子组件传递参数,但是子组件不能修改传递到子组件的参数,这就是单向数据流。

      • 方式1:子组件通过复制参数,从而只更改复制过来的参数
      <div id="root">
          <!--1.父组件向子组件传递名字为count的值-->
          <counter :count="0"></counter>
          <counter :count="5"></counter>
      </div>
      
      
      var counter = {
          // 2.子组件定义props接收count
          data:function(){
              return {
                  // 3.既然子组件无法修改父组件传来的参数
                  // 那么number为复制传过来的参数,咱们使用number
                  number:this.count
              }
          },
      
          props:['count'],
          // 4.子组件使用复制过来的number,
          template:`<div @click="handleClick">{{number}}</div>`,
          methods:{
              handleClick:function () {
                  // 并且还可以更改复制的number
                  this.number ++
              }
          }
      };
      
      var vm = new Vue({
          // el限制一个vue实例的管理范围。
          el:"#root",
          components:{
              counter:counter
          }
      });
      
      
      • 方式2:子组件向父组件传递事件
      <div id="root">
          <!--1.父组件向子组件传递名字为count的值-->
          <!--监听inc事件,一旦触发执行父组件handleIncrease函数-->
          <counter :count="0" @inc="handleIncrease"></counter>
          <counter :count="5" @inc="handleIncrease"></counter>
          <div>{{total}}</div>
      </div>
      
      var counter = {
          // 2.子组件定义props接收count
          data:function(){
              return {
                  // 3.既然子组件无法修改父组件传来的参数
                  // 那么number为复制传过来的参数,咱们使用number
                  number:this.count
              }
          },
          props:['count'],
          // 4.子组件使用复制过来的number,
          template:`<div @click="handleClick">{{number}}</div>`,
          methods:{
              handleClick:function () {
                  // 并且还可以更改复制的number
                  this.number ++;
                  // 5.子组件通过触发事件,将触发的inc事件传递给父组件
                  this.$emit('inc',1)
              }
          }
      };
      
      var vm = new Vue({
          // el限制一个vue实例的管理范围。
          el:"#root",
          data:{
            total:5,
          },
          components:{
              counter:counter
          },
          methods:{
              // 父组件定义函数
              handleIncrease:function (step) {
                  // step 为子组件 $emit的第二个参数。
                  this.total += step
              }
          }
      });
      

    5.组件参数校验与非props特性

    • 首先需要了解的是什么是props特性

      props特性其实就是,在父组件中传入了参数,恰巧子组件在props也定义了该参数的校验规则。并且子组件能使用该参数在template进行渲染
      
      <child content="hell world"></child>
      
      Vue.component('child',{
          // 子组件接收props
          props:{
              // 传入content的类型
              // 方式1:content:[String,Number]
              // 方式2:
              content:{
                  type:String,//要求传入值类型
                  required:false,//是否必填
                  defaule:"default value",//默认值
                  validator:function (value) {
                      // 传入数据长度大于5
                      return (value.length > 5)
                  }
              }
          },
         template:`<div>Child</div>`
      });
      var vm = new Vue({
          el:"#root",
      });
      
    • 非props特性

      父组件向子组件传递的是一个属性,子组件并没有声明该属性定义的内容。
      
      1.这样子组件就不能使用该属性在子组件template渲染。
      2.那么该属性会在template定义的最外层标签的标签里,显示.e.g.: <div content="hello">hello</div>
      

    6.如何给组件绑定原生事件

    • 当给一个组件标签绑定一个事件其实是自定义事件,不会触发原生事件

      <div id="root">
          <!--当给一个组件标签绑定一个事件其实是自定义事件,不会触发原生事件-->
          <child @click="handleClick"></child>
      </div>
      
      
      
      Vue.component("child",{
          // 在标签绑定事件时原生的事件
          template:"<div @click='handleClick'>Child</div>",
          methods:{
              //会触发
              handleClick:function () {
                  alert("click click")
              }
          }
      });
      var vm = new Vue({
          el:"#root",
          methods:{
              // 不会触发
              handleClick:function () {
                  alert("click")
              }
          }
      });
      
    • 那么如何触发自定义事件?$emit

      Vue.component("child",{
          // 在标签绑定事件时原生的事件
          template:"<div @click='handleClick'>Child</div>",
          methods:{
              //会触发
              handleClick:function () {
                  //通过$emit触发自定义事件
                  this.$emit("click")
              }
          }
      });
      
    • 但是这样写代码冗余,过于繁琐?通过添加事件修饰符.native

      <div id="root">
          <!--当给一个组件标签绑定一个事件其实是自定义事件,不会触发原生事件-->
          <!--通过添加.native将该事件转为原生click事件-->
          <child @click.native="handleClick"></child>
      </div>
      </body>
      <script>
          Vue.component("child",{
              // 在标签绑定事件时原生的事件
              template:"<div>Child</div>",
          });
          var vm = new Vue({
              el:"#root",
              methods:{
                  // 不会触发
                  handleClick:function () {
                      alert("click")
                  }
              }
          });
      </script>
      

    7.非父子组件传值

    • 当把一个网页拆分成多个部分,每个部分是一个组件

    • 如图红线,第二层的组件要跟第一层组件传值可以通过

      父组件通过props向子组件传值,子组件通过事件触发,向父组件传值
      
    • 如果第三层组件想传值给第一层组件呢?

      如果直接传值是不行了,只能通过第一层组件向第二层,第二层向第三层传值,返回来也是一样。
      
    • 但是这样传值相对比较复杂,比如出现如下图③的情况就相当复杂了:

    • 那么如何解决呢?一般有2种方式解决非父子组件传值,一种是vue官方提供的框架vuex,另一种使用发布订阅模式(总线机制)。
    • 示例:兄弟组件传值
    <div id="exp">
        <!--实现点击第一个子组件,里面值变成第二子组件值-->
        <!--实现点击第二个子组件,里面值变成第一子组件值-->
        <!--这两个child子组件是兄弟关系-->
        <child content="James"></child>
        <child content="Lucy"></child>
    </div>
    
    // 1.将bus属性挂载到 Vue()实例里,以后创建的Vue()实例都有bus属性
    Vue.prototype.bus = new Vue();
    Vue.component("child",{
        props:{
            content:String
        },
        // 1.1.在vue当中单向数据流,子组件不能改变父组件传递的内容
        // 所以定义一个data 返回复制后父组件传的内容
        data:function(){
            return {
                selfContent:this.content
            }
        },
        //2.给子组件绑定一个点击事件
        template:`<div @click="handleClick">{{selfContent}}</div>`,
        methods:{
            handleClick:function () {
                // 3.通过之前挂载的bus属性,
                // 这个bus又是vue实例,所以也有$emit方法。
                // 通过$emit触发change事件,同时携带当前标签的内容
                this.bus.$emit('change',this.selfContent)
            }
        },
        // 4.mounted为一个生命周期钩子,页面渲染完执行周期函数mounted
        // 监听这个bus.的改变(change事件)
        mounted:function () {
            // 5.底下function使this作用域发生,需要保存当前this
            var this_ = this;
            this.bus.$on('change',function (msg) {
                this_.selfContent = msg
            })
        }
    });
    var vm = new Vue({
        // el限制一个vue实例的管理范围。
        el:"#exp",
    });
    

    8.Vue中的插槽

    • 插槽使用场景:当子组件内容是根据父组件传递过来的DOM内容进行显示,可以使用插槽。
    <div id="exp">
        <child>
            <p>Dell</p>
        </child>
    </div>
    <script>
        //当父组件child标签内没有内容,则会显示<slot>默认内容</slot>
        Vue.component('child',{
            template:`
                <div>
                    <p>Hello</p>
                    <slot>默认内容</slot>
                </div>`
        });
        var vm = new Vue({
            el:"#exp",
        });
    
    </script>
    
    • 具名插槽

      • 给插槽取一个名字。每个插槽能按照你的要求插入具体位置。
      <div id="exp">
          <body-content>
              <div class="header" slot="header">header</div>
              <div class="footer" slot="footer">footer</div>
          </body-content>
      </div>
      
      //当父组件child标签内没有内容,则会显示<slot>默认内容</slot>
      Vue.component('body-content',{
          // 插槽设置默认值
          template:`
              <div>
                  <slot name="header"><h1>default header</h1></slot>
                  <div class="content">content</div>
                  <slot name="footer"></slot>
              </div>`
      });
      var vm = new Vue({
          el:"#exp",
      });
      

    9.Vue中的作用域插槽

    • 应用场景,当子组件做循环,其DOM结构由外部传递给子组件,子组件可以向插槽传递数据,父组件可以通过slot-scope接收数据并渲染。

      <div id="exp">
          <child>
              <!--父组件调用子组件给子组件传入一个插槽-->
              <!--此插槽为作用域插槽,必须是template标签-->
              <!--声明slot-scope表示从子组件接收的数据都放在myData里-->
              <template slot-scope="myData">
                  <!--通过myData调用每一项数据-->
                  <li>{{myData.item}}</li>
              </template>
          </child>
      </div>
      
      <script>
          Vue.component('child',{
              data:function(){
                return {
                    list:[1,2,3,4,5]
                }
              },
              // 通过v-for形成插槽,并给每个插槽绑定数据 也就是item
              template:`
                  <div>
                      <ul>
                          <slot
                              v-for="item of list"
                              :item=item
                          ></slot>
                      </ul>
                  </div>`
          });
          var vm = new Vue({
              // el限制一个vue实例的管理范围。
              el:"#exp",
          });
      </script>
      

    10.动态组件与v-once指令

    • 动态组件

      <div id="exp">
          <!--根据type动态显示相应组件-->
          <component :is="type"></component>
          <!--监听点击事件更改type数据-->
          <button @click="handleClick">change</button>
      </div>
      <script>
          Vue.component("child-one",{
              template:`<div>child one</div>`
          });
          Vue.component("child-two",{
              template:`<div>child two</div>`
          });
          var vm = new Vue({
              // el限制一个vue实例的管理范围。
              el:"#exp",
              data:{
                  type:'child-one'
              },
              methods:{
                  handleClick:function () {
                      this.type = this.type === "child-one" ? "child-two":"child-one"
                  }
              }
          });
      </script>
      
      • v-once

        看下面代码,会有什么问题

        <div id="exp">
            <child-one v-if="type === 'child-one'"></child-one>
            <child-two v-if="type === 'child-two'"></child-two>
            <button @click="handleClick">change</button>
        </div>
        Vue.component("child-one",{
            template:`<div>child one</div>`
        });
        Vue.component("child-two",{
            template:`<div>child two</div>`
        });
        var vm = new Vue({
            // el限制一个vue实例的管理范围。
            el:"#exp",
            data:{
                type:'child-one'
            },
            methods:{
                handleClick:function () {
                    this.type = this.type === "child-one" ? "child-two":"child-one"
                }
            }
        });
        

        每次点击button按钮其实相当于销毁当前组件创建另一个组件,这样频繁的切换导致创建销毁,挺耗费性能的,如果说我们定义的要切换的组件的内容相似,可以加一个v-once指令。通过v-once会将渲染的页面放在内存中,这样如果再切换回来直接从内存取,会提高静态内容展示效率,只需在子组件template里添加v-once

        Vue.component("child-one",{
            template:`<div v-once>child one</div>`
        });
        Vue.component("child-two",{
            template:`<div v-once>child two</div>`
        });
        
  • 相关阅读:
    STM32.ADC
    电源方案集
    什么叫二级域名
    android驱动学习---led实验
    Get,Post和Head具体解释
    Android 编码规范
    VC:当前不会命中断点,还没有为该文档载入不论什么符号
    经常使用的结构体
    【Facebook的UI开发框架React入门之九】button简单介绍(iOS平台)-goodmao
    记录遇到的ios下的bugs[废弃]
  • 原文地址:https://www.cnblogs.com/xujunkai/p/12229983.html
Copyright © 2011-2022 走看看