面试题4.27日部分总结

119 阅读5分钟

自定义指令

1)基本用法:

基本创建自定义指令语法:

Vue.directive('focus',{
    inserted:function(el){
    el.focus();
    }
})

自定义指令用法:

<input type="text" v-focus>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>自定义指令基本使用</title>
</head>
<body>
<div id="app">
    <input type="text" v-focus />
</div>
<script src="vue.js"></script>
<script>
    Vue.directive("focus", {
        inserted: function (el) {
            //el:表示指令所绑定的元素
            el.focus();
    },
});
const vm = new Vue({
    el: "#app",
        data: {},
    });
    </script>
  </body>
</html>

在此上代码中我们使用directive的方法创建了一个focus指令,在使用时一定要加上 v- 的形式,inserted表示的是指令的钩子函数,含义是:被绑定元素插入父节点时调用。

带参数的自定义指令

例:改变元素背景色的

Vuedirective('color',{
    inserted:function(el,binging){
        // binging表示传过来的参数
        el.style.backgroundColor=binding.value.color;
    }
})

指令用法:

<input type="text" v-color='{color:"orange"}' />

完整用法:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>自定义指令带参数</title>
    </head>
    <body>
        <div id="app">
        <input type="text" v-color="msg" />
        </div>
    <script src="vue.js"></script>
    <script>
//自定义指令-带参数
        Vue.directive("color", {
            bind: function (el, binding) {
                el.style.backgroundColor = binding.value.color;
            },
        });
        const vm = new Vue({
            el: "#app",
                data: {
                    msg: {
                        color: "blue",
                    },
                },
            });
        </script>
    </body>
</html>

上面代码定义了一个 color 指令,在使用时传递了 msg 对象,故而此对象会给binding这个参数,通过这个参数的 value 属性获取 msg 对象中 color 属性的值,然后用来设置文本框背景色 此处用了 bind 这个钩子函数:只调用一次,第一次绑定指令到元素时调用,可以在此绑定只执行一次的初始化动作。

自定义局部指令

基本语法:

directives:{
    foucs:{
    // 指令的定义
    inserted:function(el){
        el.focus()
        }
    }
}

在Vue实例中添加directives 代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>局部指令</title>
    </head>
    <body>
        <div id="app">
        <input type="text" v-color="msg" />
    </div>
        <script src="vue.js"></script>
    <script>
            const vm = new Vue({
                el: "#app",
                data: {
                msg: {
                    color: "red",
                    },
                },
            directives: {
                    color: {
                    bind: function (el, binding) {
                    el.style.backgroundColor = binding.value.color;
            },
        },
    },
});
</script>
</body>
</html>

渲染函数

vue推荐在绝大多数情况下使用模板来创建你的html,然后在一些场景中你真的需要JavaScript的完全编程的能力,也就是使用JavaScript来创建HTML,这时候就能用渲染函数,它比模板更接近编译器

render函数的基本结构

render:function(createElement){
    //createElement函数返回的结果为VNode就是虚拟dom,用js对象来模拟真实的DOM.
     return createElement(
         tag, //标签名称
         data, //传递数据
         children //子节点数组
     )
}

使用render函数来创建一个组件 代码示例:

// heading组件
    //<heading :level="1">{{title}}</heading> //这时要创建的组件
    // <h2 title=""></h2> //这时上面的组件最终渲染的结果
    Vue.component("heading", {
        props: {
            level: {
                type: String,
                required: true,
            },
    },
render(h) { //h 就是createElement函数
    return h(
        "h" + this.level, //参数1,表示要创建的元素
        this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个
子元素)
            );
        },
    });

然后就可以用heading组件了

// 使用render函数创建的头部组件
    <heading level="1">
    {{title}}
    </heading>

ofcause这里需要在data中定义title属性

data:{
    num:100,
    totalCount:0,
    users: [],
    height: 0,
    userInfo: "abc",
    title: "用户管理",
    // isShow: false,
    // showwarn: false, // 控制警告窗口的显示与隐藏
},

完整代码

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>列表渲染</title>
        <style>
            .actived {
            background-color: #dddddd;
            }
            .message-box {
            padding: 10px 20px;
            }
            .success {
            background-color: #4fc;
            border: 1px solid #42b;
            }
            .warning {
            background-color: red;
            border: 1px solid #42b;
            }
            .message-box-close {
            float: right;
            }
    </style>
</head>
<body>
    <div id="app">
        <!-- 弹窗组件 -->
        <message ref="msgSuccess" class="success">
        <!-- titile的插槽 -->
        <template v-slot:title>
            <h2>恭喜</h2>
        </template>
        <!-- 默认插槽 -->
        <template>
        添加用户成功
        </template>
     </message>
        <!-- 警告 -->
<message ref="msgWaring" class="warning">
    <!-- titile的插槽 -->
    <template v-slot:title>
    <h2>警告</h2>
    </template>
<!-- 默认插槽 -->
    <template>
    请输入用户名
    </template>
    </message>
<!-- 使用render函数创建的头部组件 -->
    <heading level="1">
    {{title}}
    </heading>
    <!-- 清空提示栏 -->
    <div class="toolbar">
    <button @click="$bus.$emit('message-close')">
    清空提示栏
    </button>
    </div>
<!-- 批量更新身高 -->
    <p>
    <input type="text" v-model.number="height" />
    <button @click="batchUpdate">批量更新用户身高</button>
    </p>
<!-- 新增用户 -->
    <user-add @add-user="addUser" v-model="userInfo"></user-add>
    <!-- 用户列表组件 -->
    <user-list :users="users"></user-list>
    <p>
    总人数:{{totalCount}}
    </p>
    </div>
    <script src="vue.js"></script>
    <script>
//创建事件总线
    Vue.prototype.$bus = new Vue();
// heading组件
//<heading :level="1">{{title}}</heading> //这时要创建的组件
// <h2 title=""></h2> //这时上面的组件最终渲染的结果
    Vue.component("heading", {
    props: {
    level: {
    type: String,
    required: true,
    },
},
    render(h) {
    return h(
    "h" + this.level, //参数1,表示要创建的元素
    this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个
子元素)
        );
    },
});
//创建弹出的组件
    Vue.component("message", {
//show表示的含义,控制弹出窗口的显示与隐藏。
//slot:表示占坑。也就是窗口中的内容,是通过外部组件传递过来的。
// props: ["show"],
    data() {
        return {
            show: false,
        };
    },
    template: `<div class='message-box' v-if="show">
                <!--具名插槽-->
                <slot name="title">默认标题</slot>
                <slot></slot>
                <span class="message-box-close" @click='toggle'>关闭</span>
            </div>`,
    mounted() {
        //给总线绑定`message-close`事件
        //也就是监听是否有`message-close`事件被触发。
        this.$bus.$on("message-close", () => {
        // this.$emit("close", false);
        //当警告窗口和提示信息的窗口,展示出来了才关闭。
        if (this.show) {
        this.toggle();
        }
    });
},
    methods: {
        toggle() {
        this.show = !this.show;
            },
        },
    });
//新增用户组件
        Vue.component("user-add", {
        // data() {
        // return {
        // userInfo: "",
        // };
        // },
        props: ["value"],
        template: `
        <div>
        <p>
            <input type="text" :value="value" @input="onInput" von:keydown.enter="addUser"
ref="inp" />
        </p>
        <button @click="addUser">新增用户</button>
        </div>
`,
    methods: {
        addUser() {
    //将输入的用户数据通知给父组件,来完成新增用户操作.
    // this.$emit("add-user", this.userInfo);
this.$emit("add-user");
    // this.userInfo = "";
    },
    onInput(e) {
        this.$emit("input", e.target.value);
    },
},
    mounted() {
        this.$refs.inp.focus();
},    
    });
    // 用户列表
Vue.component("user-list", {
    data() {
        return {
            selectItem: "",
        };
    },
        props: {
        users: {
        type: Array,
        default: [],
        },
    },
        template: `
        <div>
        <p v-if="users.length===0">没有任何用户数据</p>
        <ul v-else>
        <li
        v-for="(item,index) in users"
        :key="item.id"
        :style="{backgroundColor:selectItem===item?'#dddddd':'transparent'}"
@mousemove="selectItem=item"
>
        编号:{{item.id}} 姓名:{{item.name}}---身高:{{item.height}}
        </li>
        </ul>
        </div>
    `,
});
        new Vue({
        el: "#app",
        data: {
        num: 100,
        totalCount: 0,
        users: [],
        height: 0,
        userInfo: "abc",
        title: "用户管理",
        // isShow: false,
        // showWarn: false, // 控制警告窗口的显示与隐藏
},
        //组件实例已创建时
        async created() {
            const users = await this.getUserList();
            this.users = users;
        //批量更新用户身高
        this.batchUpdate();
        },
        methods: {
        //关闭窗口
        closeWindow(data) {
        this.isShow = data;
        this.showWarn = data;
    },
        //添加用户的信息
        addUser() {
            if (this.userInfo) {
            if (this.users.length > 0) {
                this.users.push({
                id: this.users[this.users.length - 1].id + 1,
name: this.userInfo,
});
            this.userInfo = "";
        //完成用户添加后,给出相应的提示信息
        // this.isShow = true;
            this.$refs.msgSuccess.toggle();
        }
            } else {
        // 显示错误警告信息
        // this.showWarn = true;
        this.$refs.msgWaring.toggle();
        }
    },
        //批量更新身高,动态的给users中添加身高属性
        batchUpdate() {
        this.users.forEach((c) => {
        // c.height = this.height;
        // Vue.set(c, "height", this.height);
        this.$set(c, "height", this.height);
        });
},
        getTotal: function () {
        console.log("methods");
        return this.users.length + "个";
},
        getUserList: function () {
        return new Promise((resolve) => {
        setTimeout(() => {
            resolve([
        {
            id: 1,
            name: "张三",
        },
        {
            id: 2,
            name: "李四",
        },
        {
            id: 3,
            name: "老王",
        },
        ]);
        }, 2000);
        });
    },
},
    watch: {
        users: {
            immediate: true, //立即执行
            handler(newValue, oldValue) {
            this.totalCount = newValue.length + "个人";
            },
        },
    },
});
</script>
</body>
</html>

虚拟DOM

vue通过建立一个虚拟DOM来追踪自己要如何改变真实DOM

createElement参数

createElement函数有三个参数

createElement(
//{string |Object|Function}
    //第一个参数,可以是字符串,也可以是对象或者是函数
    ‘div’
,
    // 第二个参数是对象,表示的是一个与模板中属性对应的数据对象。该参数可选
    {
    },
    //第三个参数是一个数组,表示的是子节点数组
    [
    ]
)

接下来给heading组件添加第一个属性

<heading level="1" :title="title">
{{title}}
</heading>

在上面的代码中,我们给 heading 组件动态添加了一个 title 属性。而我们知道 heading 组件,最终渲染成的 是 h1 的元素,最终效果为:< h1 title='aaa'> 的形式

// heading组件
    //<heading :level="1">{{title}}</heading> //这时要创建的组件
    // <h2 title=""></h2> //这时上面的组件最终渲染的结果
    Vue.component("heading", {
    props: {
        level: {
            type: String,
                required: true,
        },
        title: {
            type: String,
                default: "",
            },
        },
            render(h) {
        return h(
        "h" + this.level, //参数1,表示要创建的元素
        { attrs: { title: this.title } }, //参数2
        this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个
子元素)
            );
        },
    });

在上面的代码中,我们在 render 函数中给 h 函数添加了第二个参数,给最终生成的元素添加了 attrs 属性

函数式组件

组件没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法时,可以将组件标记为 functional .这意味它无状态(没有响应式数据),也没有实例(没有 this 上下文) 因为只是函数,所以渲染的开销相对来说,较小。 函数化的组件中的 Render 函数,提供了第二个参数 context 作为上下文,data、props、slots、children 以及 parent 都可以通过 context 来访问。

混入

混入( mixin )提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能,一个混入对象可以包含任意组件选 项。当组件使用混入对象时,所有混入对象的选项被“混合”进入该组件本身的选项。

// 定义一个混入对象
var myMixin={
    created:function(){
        this.hello()
        },
        methods:{
            hello:function(){
            console.log('hello world')
            }
        }
    }
       Vue.component('comp',{
            mixins:[myMixin]
})

“混入”可以提高组件的复用功能,例如:上面所写的 hello 这个方法,不仅在一个组件中使用,还会 在其它组件中使用.那么,我们的处理方式就是,可以将 hello 这个方法单独定义在一个地方,如果某个组件想要 使用,可以直接将该方法注入到组件中

插件

混入,组件封装等都可以提高组件的复用功能,但是这种方式不适合分发,也就是不适合将这些内容上传到 github 上, npm 上。而这种情况最适合通过 插件 来 实现

插件通常用来为 Vue 添加全局功能。插件的功能范围一般有下面几种:

  • 添加全局方法或者属性。例如:'element'
  • 添加全局资源
  • 通过全局混入来添加一些组件选项。例如 vue-router
  • 添加 vue实例 方法,通过把它们添加到 Vue.prototype 上实现
  • 一个库,提供自己的 API ,同时提供上面提到的一个或多个功能,例如 vue-router

插件声明

Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的 选项对象:

MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}

vue-cli 使用

npm install -g @vue/cli 通过使用 vue-clie 创建项目。