美文网首页
Vue基础知识

Vue基础知识

作者: 饥人谷_阿银 | 来源:发表于2019-06-16 20:06 被阅读0次

    构造器

    • 实例化vue时,需传入一个选项对象,它可以包括 数据、模板、挂载元素、方法和生命周期钩子

      属性与方法

    • 每个vue实例都会代理其data对象里所有的属性

    • vue实例暴露了一些有用的实例属性与方法,这些属性与方法都有前缀$,以便与代理的data属性区分

      实例生命周期

    • created钩子------在实例被创建后被调用

    • mounted----当编译好的HTML被挂载到对应的位置,这个操作完成后触发

    • updated----当data中的数据改变,并且虚拟DOM重新渲染完成后触发

    • destroyed

    • 概要: 钩子的this 指向调用它的实例

      生命周期图示

    • https://cn.vuejs.org/images/lifecycle.png

      插值

    • 文本

      • 双大括号
      • v-text
    • 纯HTML

      • v-html
    • 属性

      • v-bind(大双括号不能在属性中使用,因此需使用v-bind)
    • 使用JavaScript表达式

      指令

    • 哪些指令?

      • v-bind

      • v-on

      • v-if

      • v-for(特殊)

        v-if

        <div id="app">
        <template v-if="ok==='username'">
        用户名: <input type="text" placeholder="请输入用户名" key="name-input">
        </template>
        <template v-else>
        密码: <input type="text"  placeholder="请输入密码" key="psd-input">
        </template>
        <button @click="toggle">点击切换类型</button>
        </div>
        
        new Vue({
          el: "#app",
          data: {
            ok:'username'
          },
          methods: {
          toggle: function(todo){
              if(this.ok==='username'){
              this.ok = 'psd'
            }else{
              this.ok = 'username';
            }
          }
          }
        })
        
        

        v-for

        <div id="app">
        <ul>
          <li v-for="item in items">{{item}}</li>
        </ul>
        </div>
        
        new Vue({
        el: "#app",
        data: {
        items:['a','b','c']
        },
        methods: {
          toggle: function(todo){
              todo.done = !todo.done
          }
        }
        })
        
        
    • 修饰符

      • v-on
        • .stop 阻止单击事件冒泡 <a v-on:click.stop="doThis"></a>

        • .prevent 提交事件不再重载页面

        • .capture 添加事件侦听器时使用时间捕获模式

        • .self 只当事件在该元素本身(而不是子元素)触发时触发回调

        • 太多了,不再总结.这些都不重要,大家有空自己搜一下吧~~~~哈哈

          过滤器

    • 过滤器的目的是用于文本转换,转化成你想要的格式,还是给大家来个例子

    filters

    
       <div id="app">
            <p>{{message | changeChar}}</p>
           <button @click="changeFirstChar">改变</button>
        </div>
    
       new Vue({
        el: "#app",
        data: {
          message:'nihao'
        },
        methods: {
            changeFirstChar: function(todo){
                this.message = 'good evening'
            }
          },
          filters:{
            changeChar(value){
                    if(!value){
                return '';
              }else{
                return value.charAt(0).toUpperCase()+value.substring(1)
              }
            }
          }
        })
    
    

    缩写

    • v-bind缩写

      • 原有: <a v-bind:href="url"></a> 缩写: <a :href="url"></a>
    • v-on缩写

      • 原有:<button v-on:click="doSomeThing"></button> 缩写:<button @click="doSomeThing"></button>

        计算属性

        计算属性(减少模板{{}}的复杂度)

    • 基础例子1

    • 计算属性的两种写法

    computed

    
    <div id="app">
       {{fullName}}
    </div>
    
    new Vue({
      el: "#app",
      data: {
              firstName:'Ji',
                lastName:'RenGu'
      },
         computed:{
          fullName(){
            return this.firstName+'----'+this.lastName;
        }
      }
    })
    
    
    • 计算缓存vs方法(Methods)
      • 计算属性computed具有缓存,而methods无缓存
    • Computed属性vs 侦听器(Watch属性)
      • watch方法--观察Vue实例上的数据变动,只要指定的数据改变就会执行预定的函数

    watch

    
        <div id="app">
            {{msg}} <br> 
            改变了吗? {{isChange}}
            <button @click="change">改变</button>
        </div>
    
        new Vue({
          el: "#app",
          data: {
                msg:'欲穷千里目',
              isChange:'No'
          },
            watch:{
            //只要msg改变,这个方法就会执行
            msg(val,oldVal){
                this.isChange = 'Yes'
            }
          },
          methods:{//不得不说ES6写起来真爽
            change(){
                this.msg = '更上一层楼'
            }
          }
        })
    
    
    * computed方法
    
    
    • 计算setter 和getter

      • get和set,顾名思义,一个是获得,一个是设置,常规上来讲,计算属性中都是有get和set方法的,默认是只有getter方法,如果需要的话,自然,你也可以写一个setter方法.来个例子,诸位往下看:

      get和set

    <div id="app">
    此时的onpiece: {{onepiece}} <br>
    此时的msg: {{msg}} <br><br>
    <button @click="setName">设置name</button>
    </div>
    
    new Vue({
    el: "#app",
    data: {
    name:'Kobe',
    msg:''
    },
    methods:{
    setName(){
    this.onepiece = 'JorDan'
    }
    },
    computed:{
    onepiece:{
    get(){
    return this.name +'Bryant';
    },
    set(newVal){
    //当你给onepiece设置值的时候set就就会调用
    this.msg = newVal+'is the greatest basketball player';
    }
    }
    }
    })
    
    

    class与style绑定

    绑定HTML class

    • 对象语法
      • 基本
      • 在对象中传入多个class属性(其会与原有class共存)
      • 直接传入对象
      • 与计算属性一起使用(绑定返回对象的计算属性)
    • 数组语法
      • 简单例子
      • 三元表达式
      • 当有多个条件class时,可以在数组语法中使用对象语法
    • 用在组件上
      • 简单例子

      • 绑定HTML class例子

    绑定class的几种方式

    .classC{
      color:red;
    }
    .classD{
      font-weight:bold;
    }
    .classE{
      font-size:20px;
    }
    .classF{
      color:blue;
    }
    .classM{
      display:block;
    }
    .classN{
      display:none;
    }
    
    
    <div id="app">
     <h2>class属性绑定</h2>
    -------------------绑定变量-------------------------
    <div :class="{classA:a,classB:b}">
      绑定变量
    </div>
     -------------------绑定对象-------------------------
    <div :class="styleObj">
      绑定对象
    </div>
     -------------------绑定数组-------------------------
    <div :class="arrClass">
      绑定数组
    </div>
      -------------------绑定三元运算符-------------------------
    <div :class="m==true?'classM':'classN'">
      绑定变量
    </div>
      <button @click="toggle">toggle</button>
    </div>
    
    
    new Vue({
      el: "#app",
      data: {
       a:true,
       b:false,
       styleObj:{
        classC:true,
        classD:true
       },
       m:true,
       arrClass:['classE','classF']
      },
      methods:{
        toggle(){
            this.m=!this.m;
        }
      }
    })
    
    
    ### 绑定内联样式
    * 对象语法
        * 内联式对象语法
        * 样式对象式对象语法(更推荐)
    * 数组语法
    * 自动添加前缀
        * v-bind:style 当需要特定的前缀时如transform,vue.js会自动添加
    * 多重值
        * 从vue2.3+后,可以为一个属性添加多个值的数组,常用于含有多个前缀的情况
    例子跟上边差不了多少,懒得写了.相信大家应该也都会,哈哈哈哈~~~
    
    ## 条件渲染
    ### v-if(v-else)是真正的渲染
    * template元素与v-if
    * v-else(需要紧跟在v-if后边)
    * v-else-if(vue2.1.0新增)
    * 用key管理可复用的元素---(如果这个例子看不懂的话.可以在群里问我!!!)
        * 例子:用户名和邮箱登录界面 如果有key就不会复用,大家可以把key去试一下,然后输入看一下效果!!!
    
    
        <div id="app">
          <template v-if="ok==='username'">
              用户名: <input type="text" placeholder="请输入用户名" key="name-input">
          </template>
          <template v-else>
             密码: <input type="text"  placeholder="请输入密码" key="psd-input">
          </template>
          <button @click="toggle">点击切换类型</button>
        </div>
    
        new Vue({
          el: "#app",
          data: {
           ok:'username'
          },
          methods: {
            toggle: function(todo){
                if(this.ok==='username'){
                this.ok = 'psd'
              }else{
                this.ok = 'username';
              }
            }
          }
        })
    
    
    ### v-show(其只是简单的切换display属性)
    * v-show不支持template语法
    * v-show不支持v-else
    ### v-if VS v-show
    * v-if
        * 当条件不成立时不会渲染
        * 切换开销较大,适合不太可能变化的场景
    * v-show
        * 无论成不成立都会渲染
        * 首次渲染开销较大,但切换开销小,因此适合经常变化的场景
    ## 列表渲染
    ### v-for
    * 基本用法
        * 简单例子
        * 带有index参数
        * 使用of 替代 in
    * template v-for
        * 简单例子
    * 对象迭代 v-for
        * 基础用法
        * 带其他参数用法
    * 整数迭代 v-for
        * 例子
    * 组件和v-for
     包含所有类型的例子
    
    
    <div id="app">
    <hr>
    <strong style="border:2px solid #ccc;">遍历数组:</strong>
    <ul>
    <li v-for="item in items" >{{item}}</li>
    </ul>
    <hr>
    <strong style="border:2px solid #ccc;">遍历对象数组:</strong>
    <ul>
    <li v-for="(item,index) in pers">{{index}}--我是{{item.name}},今年{{item.age}}岁</li>
    </ul>
    <hr>
    <strong style="border:2px solid #ccc;">遍历对象:</strong>
    <ul>
    <li v-for="(value,key) in obj">
    key:{{key}} |
    value:{{value}}
    </li>
    </ul>
    </div>
    
    new Vue({
    el: "#app",
    data: {
    isOK:'true',
    items:['香蕉','苹果','烤肉'],
    pers:[{
    name:'Kobe',
    age:'40'
    },
    {
    name:'James',
    age:'38'
    }],
    obj:{
    1:'one',
    2:'two'
    }
    }
    })
    
    

    key

    • 作用

      • 用v-for更新已渲染过的列表时,它默认采用的是“就地复用”的原则,也就是如果数据项顺序发生了改变,vue将不是移动DOM元素来匹配数据项的顺序,而是简单复用此处的元素。如果想跟踪每个节点的身份,从而重用或重新排列现有元素,可使用key。(key还可用在v-if中,详见v-if中的邮箱名和用户名切换的例子)
    • 好吧,可能大家看到这里是一头雾水,不知所以,忧心忡忡,到底key有什么卵用,刚才上边的例子不是没有加key吗?好吧,不扯那没用的,通过一个例子告诉大家key到底有啥用!!!

    <div id="app">
      KEY: <input type="text" v-model="id"> 
      VALUE: <input type="text" v-model="name">
      <button @click="add">添加</button>
      <ul>
    <li v-for="item in list" :key="item.id"> 
    //此处你可以把key去了,先勾选一条,在追加一条试一下,然后加上key,勾选一条追加一条再试一下,一目了然
      <input type="checkbox" >
      {{item.id}}---{{item.name}}
    </li>
      </ul>
    </div>
    
    new Vue({
      el: "#app",
      data: {
        id:"",
        name:"",
        list:[
          {id:1, name:'李斯'},
          {id:2, name:'嬴政'},
          {id:3, name:'赵高'},
          {id:4, name:'韩非'},
          {id:5, name:'荀子'},
        ]
      },
      methods: {
          add: function(){
            this.list.unshift({id:this.id,name:this.name})
        }
      }
    })
    
    

    因为加上key默认采取的就是就地复用策略

    数组更新检测

    • 变异方法(会改变原有数组)

      • push()
      • pop()
      • shift()
      • unshift()
      • splice()
      • sort()
      • reverse()
    • 重塑数组

      • filter()
      • concat()
      • slice()
    • 注意事项
      利用索引直接设置一个项时,vue不能检测变动,如: vm.items[indexOfItem] = newValue
      那如果设置某一项的该怎么设置呢?

      • Vue.set(example1.items, indexOfItem, newValue)
      • example1.items.splice(indexOfItem, 1, newValue)
    
           <div id="app">
           <button @click="setZF">设置第二项为张飞</button>
           <button @click="setGY">设置第三项为关羽</button>
           <ul>
           <li v-for="item in list">
           <input type="checkbox" >
           {{item.id}}---{{item.name}}
           </li>
           </ul>
           </div>
    
    var vmm = new Vue({
    el: "#app",
    data: {
    id:"",
    name:"",
    list:[
    {id:1, name:'李斯'},
    {id:2, name:'嬴政'},
    {id:3, name:'赵高'},
    {id:4, name:'韩非'},
    {id:5, name:'荀子'},
    ]
    },
    methods: {
    setZF: function(){
    Vue.set(this.list,1,{id:2,name:'张飞'})
    },
    setGY:function(){
    this.list.splice(2,1,{id:3,name:'关羽'})
    }
    }
    })
    
    
    * 修改数组长度时,vue不能检测变动,如:vm.items.length = newLength
    * 只能用example1.items.splice(newLength)
    

    对与显示过滤/排序结果的两种方法

    • 过滤数组--计算属性computed例子

    • 过滤数组--方法methods例子

    计算属性应用于过滤

    
    <div id="app">
    {{specialNum}}
    </div>
    
    new Vue({
    el: "#app",
    data: {
    nums:[1,2,3,4,5,6,7,8,9]
    },
    computed:{
    specialNum(){
    return this.nums.filter((item,index)=>{
    return item%3==0;
    })
    }
    }
    })
    
    <div id="app">
    <ul>
    在v-for循环中直接嵌入方法
    <li v-for="item in fil(numbers)">{{item}}</li>
    </ul>
    </div>
    
    new Vue({
    el: "#app",
    data: {
    numbers:[1,2,3,4,5,6,7,8,9]
    },
    methods:{
    fil(nums){
    return nums.filter((item,index)=>{
    return item%3==0;
    })
    }
    }
    })
    
    

    两个简单的事件处理器

    先来一个简单小例子,v-on用来绑定事件

    
    <div id="app">
    <button @click="num+=1">增加1</button>
    {{num}}
    </div>
    
    * * *
    
    <div id="app">
    <button @click="sayHello">点击sayHello</button>
    </div>
    new Vue({
    el: "#app",
    methods: {
    sayHello: function(){
    alert('sayHello')
    }
    }
    })
    `### 内联处理器方法 * 访问原生DOM事件的例子,如果click事件不传参数,就默认把原生DOM传递进去`
    <div id="app"> //没有传参数,就是原生的!!!
    <button @click="showBtnname">显示按钮的名字</button> <br><br>
    {{msg}}
    </div>
    
    new Vue({
    el: "#app",
    data: {
    msg:''
    },
    methods: {
    showBtnname: function(e){
    this.msg = e.target.innerText;
    }
    }
    })
    
    
    • 未访问原生DOM事件的例子,如果传了参数.那么方法中接受的第一个参数就是该参数,在vue中所有的事件绑定都是这样的
    
    ----------------------------html---------------------------------
    <div id="app">
    <h2>Todos:</h2>
    <ol>
    <li v-for="todo in todos">
    <label>
    <input type="checkbox" v-on:change="toggle(todo)" v-bind:checked="todo.done">
          <del v-if="todo.done">
            {{ todo.text }}
          </del>
          <span v-else>
            {{ todo.text }}
          </span>
        </label>
      </li>
    </ol>
    </div>
    ----------------------------js---------------------------------
    new Vue({
    el: "#app",
    data: {
    todos: [
    { text: "Learn JavaScript", done: false },
    { text: "Learn Vue", done: false },
    { text: "Play around in JSFiddle", done: true },
    { text: "Build something awesome", done: true }
    ]
    },
    methods: {
    toggle: function(todo){
    todo.done = !todo.done
    }
    }
    })
    ----------------------------css---------------------------------
    body {
    background: #20262E;
    padding: 20px;
    font-family: Helvetica;
    }
    
    #app {
    background: #fff;
    border-radius: 4px;
    padding: 20px;
    transition: all 0.2s;
    }
    
    li {
    margin: 8px 0;
    }
    
    h2 {
    font-weight: bold;
    margin-bottom: 15px;
    }
    
    del {
    color: rgba(0, 0, 0, 0.3);
    }
    
    

    事件修饰符

    • .stop
      • 阻止单击事件冒泡
    • .prevent
      • 提交事件不再重载页面
    • .capture
      • 使用事件捕获模式
    • .self
      • 只有当事件在该元素本身被触发时(不包含子元素)才触发回调
    • .once
      • 事件只触发一次(vue 2.1.4新增)
    • 修饰符串联
      • 例子

    按键修饰符

    • .enter

      • keyCode
      • .enter
    • .tab

    • .delete

      • (捕获 “删除” 和 “退格” 键)
    • .esc

    • .space

    • .up

    • .down

    • .left

    • .right

    • 组合使用,单独是使用的话,和click都是一样的,这里组合使用有点特殊,使用 . 进行连接简单给个例子

    <div id="app">
    <button @click.ctrl="num++">num+1</button>
    {{num}}
    </div>
    
    new Vue({
      el: "#app",
      data: {
          num:0
      }
    })
    
    
    ### vue2.1.0新增 按键修饰符
    
    *   .ctrl
    *   .alt
    *   .shift
    *   .meta
    
        ## 表单控件绑定
    
        ### 基础用法
    
    *   文本
    
        ```
          <div id="app">
            <h2>{{msg}}</h2>
            <br>
            <input type="text" v-model="msg">
          </div>
    
          new Vue({
            el: "#app",
            data: {
             msg:'万年的msg'
            }
          })
    
        ```
    
    *   多行文本---注意了啊:在文本区域插值( `<textarea></textarea>` ) 并不会生效,应用 `v-model` 来代替
    
        ```
          <div id="app">
          <p  style="white-space: pre">
            {{msg}}
          </p>
            <br>
            <textarea type="text" v-model="msg"></textarea>
          </div>
    
        ```
    
    *   复选框
    
        *   单个复选框(直接绑定true,false)
    
            ```
            <div id="app">
            <input type="checkbox" id="checkbox" v-model="checked">
            <label for="checkbox">{{ checked }}</label>
            </div>
    
            new Vue({
              el: "#app",
              data: {
               checked:true
              }
            })
    
            ```
    
        *   多个复选框(将选中的所有value绑定到一个数组)
    
            ```
            <div id="app">
                <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
                <label for="jack">Jack</label>
                <input type="checkbox" id="john" value="John" v-model="checkedNames">
                <label for="john">John</label>
                <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
                <label for="mike">Mike</label>
                <br>
                {{checkedNames}}
            </div>
    
            new Vue({
              el: "#app",
              data: {
                checkedNames:[]
              }
            })
    
            ```
    
    *   单选按钮(绑定选中的单选框的value)
    
        ```
          <div id="app">
          <input type="radio" id="one" value="One" v-model="picked">
          <label for="one">One</label>
          <br>
          <input type="radio" id="two" value="Two" v-model="picked">
          <label for="two">Two</label>
          <br>
          <span>Picked: {{ picked }}</span>
          </div>
    
          new Vue({
            el: "#app",
            data: {
              picked:''
            }
          })
    
        ```
    
    *   选择列表(不管是单选还是多选,v-model都要绑定到select元素上)
    
        *   单选列表(绑定到被选中项的value)
    
            ```
              <div id="app">
                  <select v-model="selected">
                    <option>A</option>
                    <option>B</option>
                    <option>C</option>
                  </select>
                  <span>Selected: {{ selected }}</span>
              </div>
    
              new Vue({
                el: "#app",
                data: {
                  selected:''
                }
              })
    
            ```
    
    
    • 多选列表(绑定一个数组,数组的内容是所有的选中项的value)

      <div id="app">
      <select v-model="selected" multiple>
        <option>A</option>
        <option>B</option>
        <option>C</option>
      </select>
      <br>
      <span>Selected: {{ selected }}</span>
      </div>
      
      new Vue({
        el: "#app",
        data: {
          selected: []
        }
      })
      
    • 动态选项

      <div id="app">
      <select v-model="selected">
        <option v-for="option in options" v-bind:value="option.value">
          {{ option.text }}
        </option>
      </select>
      <span>Selected: {{ selected }}</span>
      </div>
      
      new Vue({
        el: "#app",
        data: {
               selected: 'A',
          options: [
            { text: 'One', value: 'A' },
            { text: 'Two', value: 'B' },
            { text: 'Three', value: 'C' }
          ]
        }
      })
      
    
    ### 修饰符
    
    *   .lazy
    
        *   由原有的input事件变更为change事件
    
            ```
              <div id="app">
                <input type="text" v-model.lazy="msg">
                {{msg}}
              </div>
    
              new Vue({
                el: "#app",
                data: {
                  msg:'万年的msg'
                }
              })
    
            ```
    
    *   .number
    
        *   将输入的类型转换成数字类型(NaN则还是原有类型)
    *   .trim
        *   去除两端空白
    
    算了,这点太简单
    
    ### v-model与组件
    
    ## 组件
    
    ### 使用组件
    
    *   注册
    
        *   注意事项
    
            *   在初始化根实例前一定要确保注册了组件
            *   名称最好 小写(可以使用短杆)
    
                ```
    
                <div id="app">
                <my-comp></my-comp>
                </div>
    
    
    Vue.component('my-comp',{
        template:'<h3>我是新出炉的组件</h3>'
    })
    new Vue({
      el: "#app",
      data: {
    
      }
    })
    ```
    
    
    *   局部注册
    
        ```
          <div id="app">
            <my-comp></my-comp>
          </div>
    
          new Vue({
            el: "#app",
            components:{
                'my-comp':{template:'<h3>我是新出炉的组件</h3>'}
            },
            data: {
    
            }
          })
    
        ```
    
    *   DOM模板解析说明
    
        *   自定义组件在这些元素内受限
    
            *   ul
    
            *   ol
    
            *   table
    
            *   select
    
            *   概要: 解决方案是 使用 特殊的is属性
    
                ```
                <div id="app">
                <table>
    
                ```
                 <tr>
                 <my-comp></my-comp>//注意:这样写是绝对错误的,因为tr中只允许有td,这样写他是不认识滴
                 </tr>
    
                ```
    
                </table>
                </div>
                xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 上边是错误的
    
    
        ---------------------------------下边是正确的-----------------------------------
        <div id="app">
         <table>
           <tr>
             <td is="my-comp"></td>
           </tr>
         </table>
        </div>
    
        new Vue({
          el: "#app",
          components:{
              'my-comp':{
                    template:'<td>我是组件td</td>'
            }
          },
          data: {
    
          }
        })
        ```
    
    • 不受限的情况--使用字符串模板

      • <script type="text/x-template"> 怎么用呢?给大家来个例子吧!

        -------------------------------HTML-----------------------------------------
        <div id="app">
         <table>
           <tr>
           <template>
               <my-comp></my-comp>
           </template>
           </tr>
         </table>
        </div>
        
        <script type="text/x-template" id="myComponent">
                    <td>This is a component!</td>
        </script>
        
        -----------------------------------JS----------------------------------
        new Vue({
          el: "#app",
          components:{
              'my-comp':{
                    template:'#myComponent'
            }
          },
          data: {
        
          }
        })
        
      • JavaScript内联模板字符串(第二种也给大家解释一下是什么意思,什么是字符串模板)

        <div id="app">
         <table>
           <tr>
           <template>  //这个就是字符串模板
               <my-comp></my-comp>
           </template>
           </tr>
         </table>
        </div>
        
      • .vue组件 (第三种不解释了,用了那么多遍了,要是还不会,我就开始疯狂嘲笑你)

    • data必须是函数,在组件中使用data中定义的数据,必须使用函数返回,其实这事要说为啥,还得从根上说,我自己的理解,最根本的三个字就是作用域,目的就是为了防止组件中使用的data和vue实例中的data进行相互污染,有机会的话可以给大家讲一下,但是这不是三句两句就能讲清楚的,门票一人5毛怎么样?

      <div id="app">
      <mycomp></mycomp>
      </div>
      
      new Vue({
        el: "#app",
        components:{
            'mycomp':{
                  template:'<button>{{btncount}}</button>',
             data(){
                return {btncount:8}
              }
          }
        },
        data:{
            btncount:10
        }
      })
      

    Prop(子组件从父组件获得数据)

    • 使用prop传递数据

      •   <div id="app">
              <child msg="我是来自于父组件的内容"></child>
          </div>
        
          new Vue({
            el: "#app",
            components:{
                'child':{
                  props:['msg'],
                  template:'<h2>{{msg}}</h2>'
              }
            }
          })
        
        
      • 动态绑定父组件中的数据

              <div id="app">
                <input type="text" v-model="fathertext">
                    {{fathertext}}
                <child :childText="fathertext"></child>
              </div>
    
              new Vue({
                el: "#app",
                components:{
                    'child':{
                      props:['childtext'],
                      template:'<h1>{{childtext}}</h1>'
                  }
                },
                data: {
                    fathertext:''
                }
              })
    
    
    • props注意事项

    • 一般情况下是数组形式,如果要想规定props的数据类型(后面用中括号 [ ])。默认值等(见props验证),则是对象了(后面用花括号 { })

    • 关于命名:要不然全小写,要不然kebabCase(驼峰式),kebab-case(短横线隔开式)Vue 能够正确识别出小驼峰和下划线命名法混用的变量,如这里的forChildMsgfor-child-msg是同一值。

    • ,如果出不来,先检查一下命名,看个例子:

        
        <div id="app">
          <input type="text" v-model="msg">
          <child :childMsg="msg"></child>
        </div>
      
        new Vue({
          el: "#app",
          components:{
              child:{
                template:'<h1>{{childMsg}}</h1>',
                  props:['childMsg']
            }
          },
          data: {
           msg:'apple'
          }
        })
      
      
    • 动态Prop(使用v-bind):在模板中,要动态地绑定父组件的数据到子组件模板的 props,和绑定 Html 标签特性一样,使用v-bind绑定

      • 局部注册组件
      • 全局注册组件
    • 字面量语法vs动态语法

    • 单向数据流

      • 解释

        • 父组件数据更新后,子组件的所有prop都会更新为最新值,但是反过来就不会。(注意 :如果prop为数组或对象时,子组件改变prop,父组件的状态也会受到影响,因为数组或对象是引用类型,他们指向同一个内存空间。)如果子组件的prop值被修改,则vue会给出警告。试一下下边这个例子

          <div id="app">
          <parent></parent>
          </div>
          
          let childNode = {
           template: `
               <div class="child">
                <div>
                 <span>子组件数据</span>
                 <input v-model="forChildMsg"/>
                </div>
                <p>{{forChildMsg}}</p>
               </div>`,
           props: {
            "for-child-msg": String
           }
          };
          let parentNode = {
           template: `
               <div class="parent">
                <div>
                 <span>父组件数据</span>
                 <input v-model="msg"/>
                </div>
                <p>{{msg}}</p>
                <child :for-child-msg="msg"></child>
               </div>
              `,
           components: {
            child: childNode
           },
           data() {
            return {
             msg: "default string."
            };
           }
          };
          
          new Vue({
            el: "#app",
            components:{
                parent:parentNode
            }
          })
          
          
      • 特殊情况应对方法

        • prop作为初始值传入后,可能子组件想把它当做局部数据来用的情况

          • 方法:定义一个局部变量,并用prop的值初始化它

            props: ['initialCounter'],
            data: function () {
              return { counter: this.initialCounter }
            }
            //直接使用counter作为子组件的局部变量就可以了
            
            
        • prop作为初始值传入,可能子组件处理成其他数据输出的情况,比如处理成去空格并大写

          • 方法:定义一个计算属性,处理prop的值并返回

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

      • 例子--代码篇

        Vue.component('example', {
          props: {
            // 基础类型检测 (`null` 意思是任何类型都可以)
            propA: Number,
            // 多种类型
            propB: [String, Number],
            // 必传且是字符串
            propC: {
              type: String,
              required: true
            },
            // 数字,有默认值
            propD: {
              type: Number,
              default: 100
            },
            // 数组/对象的默认值应当由一个工厂函数返回
            propE: {
              type: Object,
              default: function () {
                return { message: 'hello' }
              }
            },
            // 自定义验证函数
            propF: {
              validator: function (value) {
                return value > 10
              }
            }
          }
        })
        
        

    自定义事件(子组件将数据传回父组件)

    • 使用v-on绑定自定义事件

      • 给组件绑定自定义事件例子(用v-on来监听子组件触发的事件)

      • 给组件绑定原生事件例子--使用native修饰符

        <div id="app">
          <btncomp @click.native="alertE"></btncomp>
        </div>
        
        new Vue({
          el: "#app",
             components:{
              btncomp:{
                template:'<button>点击我弹出</button>'
            }
          },
          methods:{
              alertE(){
                alert(777)
            }
          }
        })
        
        
    • .sync修饰符(vue 2.3)

      • 目的:使父子组件实现prop类似“双向数据绑定”(默认子组件无法更改prop的值,上边已经说到了,但是使用sync后子组件可以改变prop 的值,并传回父组件)

      • 使用范例

          <div id="app">
              <child :name.sync="name"></child>  //其实不加也能更改,但是会报错
              <button type="button" @click="changePropsInFather">在父组件中将props值改变为'props'</button>
            </div>
        
              Vue.component('Child', {
                template: `<h1 @click="changePropsInChild">hello, {{name}}</h1>`,
                props: {
                  name: String,
                },
                methods:{
                  changePropsInChild(){
                    this.name = 'I am from child'
                  }
                },
              })
              // 实例化一个Vue对象
              const app = new Vue({
                el: '#app',
                data(){
                  return {
                    name: 'world'
                  }
                },
                methods:{
                  changePropsInFather(){
                    this.name='I am from father'
                  },
                },
              })
        
        
    • 使用自定义事件的表单输入组件

      • v-model的语法糖(可能之前我在CNODE课程中讲过,但是提的不是特别的仔细,这里还是给大家再说一下)

           <div id="app">
               <input v-model="price">
           </div>
        
            new Vue({
               el: '#app',
               data: {
                    price: ''
               }
           });
        
        

        我们对v-model已经再熟悉不过了,一般都是像上边这样的用法,但是v-model只是一个语法糖,它的真身是下边这样:

          <div id="app">
          <input type="text" :value="price" @input="price = $event.target.value">{{price}}
          </div>
        
            new Vue({
               el: '#app',
               data: {
                    price: ''
               }
           });
        
        
    * 例子
    
        * html及实例部分和注册组件部分
    
          ```
          <div id="app">
            <price-input :value="price" @input="isinputing"></price-input>
            {{price}}
          </div>
    
          new Vue({
            el: "#app",
            components:{
                'price-input':{
                  template:"<input type='text' @input='update($event.target.value)' />",
                props:['value'],
                methods:{
                    update(val){
                      this.$emit('input',val)
                  }
                }
              }
            },
            data: {
              price:''
            },
            methods: {
                isinputing: function(val){//此处的value就是子组件传递过来的
                  this.price = val;
              }
            }
          })
          ```
    
    

    非父子组件通信

    • 非父子组件通信(1 父传子是用props 2 子传父在vue中是不允许的,因为vue只允许单向数据传递,这时候我们可以通过触发事件来通知父组件改变数据,从而达到改变子组件数据的目的. 3 那么非父子组件之间通信怎么搞??????)

      • 简单的场景---采用空实例作为中央事件总线,原理就是找一个人来当作一个中转站!

        
         <div id="app1" @click="toApp2">
            我是组件一,点击我给二传值
          </div>  <br>
           <div id="app2">
             {{app2msg}}
           </div>
        
        var bus = new Vue();  // 创建事件中心,创建中转站
        new Vue({
          el: "#app1",
          data: {},
          methods: {
              toApp2: function(){
                bus.$emit('change','上山打老虎')  //使用中转站触发
            }
          }
        })
        
        new Vue({
          el: "#app2",
          data: {
              app2msg:''
          },
          created(){
              bus.$on('change',(val)=>{
                this.app2msg = val; //在组件二创建完成的时候就使用中转站进行监听
            })
          }
        })
        
        
    * 复杂的场景---专门的状态管理模式vuex
    
    

    使用Slot分发内容

    • 内容分发概念

      • 为了让组件可以组合(如本子主题的例子),因此需要混合父组件的内容与子组件的自己模板,这一过程就称作内容分发。

          <app>
            <app-header></app-header>
            <app-footer></app-footer>
          </app>
        
          之前我们的组件,如果给app指定了模板,那么里边的app-header和foot组件的内容就会被覆盖,因此,为了让他们能够组合.需要混用,这就是内容分发
        
        
    • 编译作用域

      • 分发内容是在父作用域内编译的
    • 单个slot(无具名slot)

      • 为什么用slot

        • 当父组件中有内容(即自定义的标签名之间有元素--见本子主题的例子) 子组件模板中无slot时,则父组件中的内容会被丢弃。

            <div id="app">
              <my-comp>
                <p>我是组件中的内容</p>  //这个p会被覆盖
              </my-comp>
            </div>
          
            new Vue({
              el: "#app",
              components:{
                  'my-comp':{
                    template:'<h1>我是一个组件</h1>'
                }
              }
            })
          
          
            * 那么单个slot怎么用呢?
    
                ```
                <div id="app"> 
                <children> 
                <span>12345</span> 
                <!--上面这行不会显示--> 
                </children> 
                </div> 
    
                var vm = new Vue({ 
                el: '#app', 
                components: { 
                children: { //这个无返回值,不会继续派发 
                    template: "<button><slot></slot>(我是button)</button>"
                } 
                } 
                }); 
                ```
    
    * 当父组件中有内容时
        * 子组件中的slot会被父组件中内容所替换。(slot标签也会被替换掉)
    * 当父组件中无内容时
        * 子组件中slot内容会被显示出来
    
    
    • 具名slot

      • 用法:保子引父(保持子组件模板,引入父组件参数)--严格按照子组件的模板顺序来即:遇到具名slot对应的元素就渲染相应的元素,遇到不具名的slot,则会渲染除了具名slot对应的元素以外的所有元素。

          <div id="app">
            <children>
              <span slot="first">12345</span>
              <span slot="second">56789</span>
              <!--上面这行不会显示-->
            </children>
          </div>
        
          var vm = new Vue({ 
          el: '#app', 
          components: { 
            children: { //这个无返回值,不会继续派发 
              template: "<button><slot name='first'></slot>我是button<slot name='second'></slot>所以使用button标签</button>"
            } 
          } 
          }); 
          总结:说白了,就是多一个name属性.没啥稀奇玩意
        
        
    • 作用域插槽(特殊的插槽)

      • 作用:使用可复用模板替代已渲染元素

      • 用法:同具名slot类似,都是严格按照子组件的模板顺序渲染,只不过遇到slot元素时会将父组件中的template元素里的元素全部渲染

        • 列表组件例子

          
          <div id="app">
          <child :items="items">
          <template slot="item" scope="props">
          <!--必须存在的具有 scope属性的 template元素(作用域插槽的模板), props临时的变量名称,接受子组件中传递的props对象-->
          <!--slot = “item”是具名 slot的用法。-->
          <li>
          {{props.tex}}
          <!--引用子组件中绑定的tex属性值。-->
          </li>
          </template>
          </child>
          </div>
          
          
            Vue.component('child',{
                    props:["items"],
                    template:'<ul><slot name="item" v-for="item in items" v-bind:tex="item.text"></slot></ul>'
                });
    
            new Vue({
                el:'#app',
                data:{
                    items:[
                        {text:'老虎'},
                        {text:'棒子'},
                        {text:'鸡'}
                    ]
                }
            })
            ```
    
    

    动态组件

    • 使用is属性(注意,is前使用了v-bind!!!通过is来决定那个组件被渲染显示 )

      
         <div id="app">
            <component v-bind:is="show"></component>
            <button v-on:click="changeShow">change show</button> 
         </div>
      
              var app=new Vue({
                    el:'#app',
                    data:{
                        show:'tem1'
                    },
                    components:{
                        tem1:{
                            template:'<div>11111111111</div>'
                        },
                          tem2:{
                            template:'<div>22222</div>'
                        },
                          tem3:{
                            template:'<div>333333</div>'
                        }
                    },
                    methods:{
                        changeShow:function(){
                            if(this.show=='tem1'){
                                    this.show='tem2'
                            }else  if(this.show=='tem2'){
                                    this.show='tem3'
                            }else{
                                 this.show='tem1'
                            }
                        }
                    }
                })
      
      
    • keep-active

      • 作用:可保留组件状态或避免重新渲染(包裹动态组件时会缓存不活动的组件实例而不是销毁它们)配合 <keep-alive>使用时,可以保留组件状态避免重新渲染(和v-show 比较的差别是v-show 是一开始就渲染的所有组件,而keep-alive 并不是一开始就渲染好所有组件,而已保留渲染过的组件

      • 注意事项:使用环境应该是较大页面频繁切换的情景下

      • 用法

                  <div id="app">
                      <component v-bind:is="show"></component>
                      <button v-on:click="changeShow">change show</button>
                  </div>
        
                           var app=new Vue({
                      el:'#app',
                      data:{
                          show:'tem1'
                      },
                      components:{
                          tem1:{
                              template:'<div>11111111111</div>'
                          },
                            tem2:{
                              template:'<div>22222</div>'
                          },
                            tem3:{
                              template:'<div>333333</div>'
                          }
                      },
                      methods:{
                          changeShow:function(){
                              if(this.show=='tem1'){
                                      this.show='tem2'
                              }else  if(this.show=='tem2'){
                                      this.show='tem3'
                              }else{
                                   this.show='tem1'
                              }
        
                          }
                      }
        
                  })
        

    相关文章

      网友评论

          本文标题:Vue基础知识

          本文链接:https://www.haomeiwen.com/subject/mdzgfctx.html