当前位置: 移动技术网 > IT编程>开发语言>JavaScript > 荐 vue基础及高级用法(一)

荐 vue基础及高级用法(一)

2020年07月12日  | 移动技术网IT编程  | 我要评论

1. 插值表达式

{{xxx}}的形式,可以是值,也可以是表达式(不能是 js 语句,比如if、for)

<div id="app">
    <p>{{msg}}</p>
    <p>{{ok? '1':'2'}}</p>
</div>
var app = new Vue({
  el: '#app',
  data: {
    msg: 'Hello Vue!',
    ok: true
  }
})

展示效果
展示效果

2. 指令

v-cloak 指令 :直到编译结束显示

<div v-cloak>
  {{ message }}
</div>
[v-cloak] {
  display: none;
}

v-text 指令 :用于更新 html 标签里的内容

<div id="app">
    <p v-text="msg"></p>
    <!-- 和下面的一样 -->
    <p>{{msg}}</p>
</div>
var app = new Vue({
  el: '#app',
  data: {
    msg: 'message'
  }
})

效果展示

效果展示

v-html 指令 :用于更新并解析 html 标签(不安全)

在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html

效果展示

<div id="app">
    <p v-html="msg"></p>
</div>
var app = new Vue({
    el: '#app',
    data: {
        msg: '<span style="color:red">红色字体</span>'
    }
})

效果展示

v-bind 指令 :动态属性绑定

<div id="app">
    <p v-bind:id="pid">动态属性 id</p>
    <p :id="aid">简写形式</p>
</div>
var app = new Vue({
    el: '#app',
    data: {
        pId: 'pid',
        aId: 'aid'
    }
})
class与style
<div id="app">
    <p :class="{ black: isBlack, yellow: isYellow }">使用 class</p>
    <p :class="[black, yellow]">使用 class (数组)</p>
    <p :style="styleData">使用 style</p>
</div>
var app = new Vue({
    el: '#app',
    data() {
        return {
            isBlack: true,
            isYellow: true,

            black: 'black',
            yellow: 'yellow',

            styleData: {
                fontSize: '40px', // 转换为驼峰式
                color: 'red',
                backgroundColor: '#ccc' // 转换为驼峰式
            }
        }
    }
})

v-if、v-else-if、v-else 指令 :有条件地渲染元素

<div id="app">
    <p v-if="type === 'a'">A</p>
    <p v-else-if="type === 'b'">B</p>
    <p v-else-if="type === 'c'">C</p>
    <p v-else>other</p>
</div>
var app = new Vue({
    el: '#app',
    data() {
        return {
            type: 'a'
        }
    }
})

v-show 指令 :有条件地控制css display显示或隐藏元素

<div id="app">
    <p v-show="type === 'a'">A by v-show</p>
    <p v-show="type === 'b'">B by v-show</p>
</div>
var app = new Vue({
    el: '#app',
    data() {
        return {
            type: 'a'
        }
    }
})
v-if 与 v-show 的使用场景

频繁切换,使用 v-show 较好;
运行时条件很少改变,则使用 v-if 较好。

v-for 指令 :循环渲染元素

  • 不要把 v-if 和 v-for 同时用在同一个元素上。
<div id="app">
    <p>遍历数组</p>
    <ul>
        <li v-for="(item, index) in listArr" :key="item.id">
            {{index}} - {{item.id}} - {{item.title}}
        </li>
    </ul>

    <p>遍历对象</p>
    <ul >
        <li v-for="(val, key, index) in listObj" :key="key">
            {{index}} - {{key}} -  {{val.title}}
        </li>
    </ul>
</div>
var app = new Vue({
    el: '#app',
    data() {
        return {
            flag: false,
            listArr: [
                { id: 'a', title: '标题1' }, // 数据结构中,最好有 id ,方便使用 key
                { id: 'b', title: '标题2' },
                { id: 'c', title: '标题3' }
            ],
            listObj: {
                a: { title: '标题1' },
                b: { title: '标题2' },
                c: { title: '标题3' },
            }
        }
    }
})

为什么要有key,且不用index(即数组的下标)来作为key。

虚拟dom中,diff算法会根据selkey来判断节点是否可以复用。

v-on 指令 :绑定监听事件

  • event 是原生的。
  • 事件被挂载到当前元素,和 DOM 事件一样。
用 vue 绑定的事件,组建销毁时会自动解绑。
自己绑定的事件,需要自己销毁!!!
<div id="app">
    <p>{{num}}</p>
    <button v-on:click="increment1">+1</button>
    <button @click="increment1">简写形式</button>
    <button @click="increment2(2, $event)">+2</button>
</div>
var app = new Vue({
    el: '#app',
    data() {
        return {
            num: 0
        }
    },
    methods: {
        increment1(event) {
            console.log(event) // 是原生的 event 对象
            console.log(event.target) // 注意,事件是被注册到当前元素的,和 React 不一样
            this.num++
        },
        increment2(val, event) {
            this.num = this.num + val
        },
        loadHandler() {
            // do some thing
        }
    },
    mounted() {
        window.addEventListener('load', this.loadHandler)
    },
    beforeDestroy() {
        //【注意】用 vue 绑定的事件,组建销毁时会自动被解绑
        // 自己绑定的事件,需要自己销毁!!!
        window.removeEventListener('load', this.loadHandler)
    }
})

v-model 指令 :表单数据的双向绑定

修饰符
  • .lazy - 取代 input 监听 change 事件
  • .number - 输入字符串转为有效的数字
  • .trim - 输入首尾空格过滤
表单用法
<div id="app">
    <p>输入框: {{name}}</p>
    <input type="text" v-model.trim="name"/>
    <input type="text" v-model.lazy="name"/>
    <input type="text" v-model.number="age"/>

    <p>多行文本: {{desc}}</p>
    <textarea v-model="desc"></textarea>
    <!-- 注意,<textarea>{{desc}}</textarea> 是不允许的!!! -->

    <p>复选框 {{checked}}</p>
    <input type="checkbox" v-model="checked"/>

    <p>多个复选框 {{checkedNames}}</p>
    <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>

    <p>单选 {{gender}}</p>
    <input type="radio" id="male" value="male" v-model="gender"/>
    <label for="male"></label>
    <input type="radio" id="female" value="female" v-model="gender"/>
    <label for="female"></label>

    <p>下拉列表选择 {{selected}}</p>
    <select v-model="selected">
        <option disabled value="">请选择</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>

    <p>下拉列表选择(多选) {{selectedList}}</p>
    <select v-model="selectedList" multiple>
        <option disabled value="">请选择</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
</div>
var app = new Vue({
    el: '#app',
    data() {
        return {
            name: '双越',
            age: 18,
            desc: '自我介绍',

            checked: true,
            checkedNames: [],

            gender: 'male',

            selected: '',
            selectedList: []
        }
    }
})
拓展:v-model实现原理
  • v-model的本质是一个语法糖。
  • v-model在组件中不建议使用,自行设计即可。
<input v-model="sth" />
第一行的代码其实只是第二行的语法糖
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />
然后第二行代码还能简写成这样:
<input :value="sth" @input="sth = $event.target.value" />
如果是复选框
<input type="checkbox" :checked="status" @change="status = $event.target.checked" />

原理:每当输入框内容发生变化时,就会触发oninput,把最新的value传递给 绑定的值。

v-slot 指令 :插槽,通过父组件决定子组件模板显示

普通插槽

father 模板:

<child>
  <p>yy</p>
</child>

child 模板:

<div>
  <P>Hello</P>
  <slot>父组件没有提供内容的默认值</slot>
</div>

最终的效果相当于

<div>
  <P>Hello</P>
  <p>yy</p>
</div>
具名插槽

父组件在 <template> 元素上使用 v-slot

<body-content>
  <template v-slot:header>
  <!-- v-slot 缩写 -->
  <!-- <template #header> -->
    <div class="header">header</div>
  </template>
  <template v-slot:footer>
    <div class="footer">footer</div>
  </template>
</body-content>

子组件通过 name 属性,定义 的名字

<div>
  <slot name="header"></slot>
  <div class='content'>content</div>
  <slot name="footer"></slot>
</div>
v-slot 只能添加在 <template> 上,以下情况例外
当只有默认插槽时,可以把 v-slot 直接用在组件上
<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>
作用域插槽

父组件用子组件的数据填充插槽

<div id="app">
    <current-user>
        <template v-slot:default="slotProps">
            子组件传递的姓名{{ slotProps.user }} 年龄{{ slotProps.age}}
        </template>
    </current-user>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    Vue.component('current-user', {
        template: `
        <span>
        <slot v-bind:user="user" age="250">
            {{ user }}
        </slot>
        </span>
        `,
        data: function() {
            return {
                user: '姓名'
            };
        }
    })
    const app = new Vue({
        el: '#app',
    });
</script>

3. 数据

computed 计算属性

计算属性的结果会被缓存,依赖的data变化才会重新计算。

<div id="app">
    <p>num {{num}}</p>
    <p>num {{num}}</p>
    <p>double1 {{double1}}</p>
    <p>double1 {{double1}}</p>
    <input v-model="double2"/>
</div>
var app = new Vue({
    el: '#app',
    data:{
        num: 20
    },
    computed: {
        double1() {
            console.log('double1')
            return this.num * 2
        },
        double2: {
            get() {
                console.log('double2get')
                return this.num * 2
            },
            set(val) {
                console.log('double2set')
                this.num = val/2
            }
        }
    }
})

watch 监听属性

监听数据的变化。

<div id="app">
    <input v-model="name"/>
    <input v-model="info.city"/>
</div>
    var app = new Vue({
        el: '#app',
        data() {
            return {
                name: '双越',
                info: {
                    city: '北京'
                }
            }
        },
        watch: {
            name(oldVal, val) {
                // eslint-disable-next-line
                console.log('watch name', oldVal, val) // 值类型,可正常拿到 oldVal 和 val
            },
            info: {
                handler(oldVal, val) {
                    // eslint-disable-next-line
                    console.log('watch info', oldVal, val) // 引用类型,拿不到 oldVal 。因为指针相同,此时已经指向了新的 val
                },
                deep: true // 深度监听
            }
        }
    })

4. 生命周期

vuelife
常用

  • beforeCreate::在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。(服务器端渲染期间被调用)
  • created:可以访问到data,(服务器端渲染期间被调用)
  • beforeMount : 在挂载开始之前被调用:相关的渲染函数首次被调用
  • mounted : el 被新创建的 vm.$el 替换, 挂载成功
一般在此时调用ajax,js是单线程的,dom加载完才会进行异步操作
// mounted 不保证子组件都被挂载。如果等到视图渲染完毕,可以在 mounted 内部使用 vm.$nextTick:
mounted: function () {
    this.$nextTick(function () {
        // Code that will run only after the
        // entire view has been rendered
    })
}
  • beforeUpdate : 数据更新时调用
  • updated :组件 DOM 已经更新完毕
// updated 不保证子组件都被重绘。如果等到视图重绘完毕,可以在 updated 里使用 vm.$nextTick:
updated: function () {
    this.$nextTick(function () {
        // Code that will run only after the
        // entire view has been re-rendered
    })
}
  • beforeDestory():组件销毁前。
一般在此时解绑自定义事件和清除定时器。
  • destoryed():组件销毁之后

不常用

  • activated:当组件激活的时候调用
  • deactivated:当组件停用的时候调用
  • errorCaptured:当捕获一个来自子孙组件的错误时被调用。(服务器端渲染期间被调用)

拓展:父子组件的生命周期

  • 加载渲染过程

父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

  • 子组件更新过程

父beforeUpdate->子beforeUpdate->子updated->父updated

  • 父组件更新过程

父beforeUpdate->父updated

  • 销毁过程

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

5. 组件间的通讯

常见的有三种方式:父子间传值、非父子间自定义事件传值、vuex。

  • 父传子 用 props
<div id="app">
    <div>{{pmsg}}</div>
    <menu-item :title='ptitle' :content='ptitle'></menu-item>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
    //父组件向子组件传值-基本使用
    Vue.component('menu-item', {
        props: ['title', 'content'],
        data: function() {
            return {
                msg: '子组件本身的数据'
            }
        },
        template: `
            <div>
                <p>{{msg}}</p>
                <p>{{title}}</p>
                <p>{{content}}</p>
            </div>`
    });
    var vm = new Vue({
        el: '#app',
        data: {
            pmsg: '父组件中内容',
            ptitle: '动态绑定属性'
        }
    });
</script>

  • 子传父 用 $emit

子组件写法
this.$emit(‘fa’, this.num)

父组件写法
<button-add @fa=“getNum”>

<div id="app">
    <div>{{sonNum}}</div>
    <!--    vue定义好的组件,可以重复使用·-->
    <button-add @fa="getNum"></button-add>
</div>
<!--引入vue-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    // 注册全局对象,要写在vue实例的上面
    Vue.component('button-add', {
        data: function () {
            return {
                num: 0
            }
        },
        template: `<button @click="add">{{num}}</button>`,
        methods: {
            add: function () {
                this.num = this.num + 1
                this.$emit('fa', this.num)
            }
        }
    })
    // 创建vue实例
    var vm = new Vue({
        el: '#app',
        data: {
            sonNum: 0
        },
        methods: {
            getNum: function (son) {
                this.sonNum = son
            }
        }
    })
</script>
  • 非父子组件(兄弟组件),需要创建新的vue实例来自定义事件

用法

  1. 创建一个新的vue对象
var newvue = new Vue()
  1. 触发事件
newvue.$emit('自定义事件名', 参数)
  1. 监听事件
newvue.on('自定义事件名', 触发方法名)
  1. 销毁事件:需要自行销毁
newvue.off('自定义事件名')

示例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <div>父组件</div>
    <div>
      <button @click='handle'>销毁事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      兄弟组件之间数据传递
    */
    // 提供事件中心
    var hub = new Vue();

    Vue.component('test-tom', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>TOM:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          hub.$emit('jerry-event', 2);
        }
      },
      mounted: function() {
        // 监听事件
        hub.$on('tom-event', (val) => {
          this.num += val;
        });
      }
    });
    Vue.component('test-jerry', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>JERRY:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          // 触发兄弟组件的事件
          hub.$emit('tom-event', 1);
        }
      },
      mounted: function() {
        // 监听事件
        hub.$on('jerry-event', (val) => {
          this.num += val;
        });
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
        
      },
      methods: {
        handle: function(){
          hub.$off('tom-event');
          hub.$off('jerry-event');
        }
      }
    });
  </script>
</body>
</html>

本文地址:https://blog.csdn.net/weixin_43745003/article/details/107279151

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网