自定义指令
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表示的是指令的钩子函数,含义是:被绑定元素插入父节点时调用。
带参数的自定义指令
例:改变元素背景色的
Vue。directive('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 创建项目。