在我们使用 vue 之前我们需要事先得到 一个 vue 实例对象,我们需要传递一个对象用于描述你的 vue 实例。
const app = new Vue({});
el
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例
const app = new Vue({
el: "#app",
// el: document.getElementById("app"),
});
template
一个字符串模板作为 Vue 实例的标识使用。模板将会替换挂载的元素。你可以回忆一下之前学过的 innerHTML 的作用。
const app = new Vue({
el: "#app",
template: "hello world",
});
render
字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode。如果实例化 Vue 中同时传递了 template 和 render 那么,template 会直接忽略【因为其实 template 也会走 render 的流程】。
// render 函数中通过 createElement 创建虚拟节点(所谓虚拟节点就是使用js对象模拟DOM节点,然后在特定的方法中再解析成为真正的节点。这样做的好处是减少了重绘和回流),写法相对而言比较固定。
//createElement 中需要传递三个参数。第一个是你需要渲染什么样的节点。第二个参数是该节点的描述,第三个是该节点的子节点数组。
const app = new Vue({
el: "#app",
render: function(createElement) {
return createElement(
// 要渲染的标签名称
"div",
// 该标签的描述
{
// 可以写内置样式
style: {
color: "red",
border: "1px solid black",
},
// 可以指定 class
class: {
cls1: true,
cls2: false
},
// 普通的 HTML 特性
attrs: {
id: 'foo',
name:"foo"
},
// 主要用于父子组件通讯
props: {
},
// 事件监听
on:{
// 指定 作用域,同时传值
click: handle.bind(window, 3),
}
// 仅用于组件,用于监听原生事件,对于使用 `vm.$emit` 触发的事件不敏感。
nativeOn: {
click: handle.bind(window, 3),
},
// 自定义指令
directives: [],
// 插槽名称
slot:"",
// 特殊属性
key: '',
ref: '',
},
// 该标签的子节点数组
[
"text", // 文本节点直接写就可以
createElement(
"div",
{
style: {
color: "blue",
border: "1px solid black",
},
},
"hahah"
),
]
);
},
});
给已有的对象数据添加新的属性
data: {
title: "test",
user: {},
},
// 下面两种方式都能监听数据变化
Vue.set(app.user, 'gender', '男');
// 实例.$set 是 Vue.set 的别名
app.$set(app.user, 'gender', '男');
const app = new Vue({
el: "#root",
template: "{{title}}",
data: {
title: "测试数据",
},
// 当然如果是后面再去添加 watch,还需要手动删除监听
/*
const uw = app.$watch("title",(newVal,oldVal)=>{})
uw() // 只需要执行一遍返回的函数,就不再监听 title 的变化
*/
watch: {
title(newVal, oldVal) {
// ...
},
},
});
console.log(app.$data); // data 的部分
console.log(app.$el); // 挂载节点
console.log(app.$options); // 传入Vue的整个对象【包含默认属性】在这里面对 data 重新赋值是无效
app.$options.render = (h) => {
// 那么当数据发生变化的时候,在下一次渲染的时候会更新视图
return h("div", {}, "test");
};
console.log(app.$root === app); // true
// 自定义事件监听
app.$on("someEventName", (...args) => {
// do something
});
/*
// 只监听一次
app.$once("someEventName", (...args) => {
// do something
});
*/
// 在适当的时候触发事件【常用于父子组件通讯】
app.$emit("someEventName", 1, 2);
// 如果在 data 中没有定义属性,那么在后面新增属性的时候并不会监听变化
data: {
obj: {
}
}
app.obj.newKey = 123;
// 可以采取强制组件渲染的方式【会降低性能】
app.$forceUpdate();
/*
// 当然更好的方式是
app.$set(app.obj,"newKey",123);
*/
// 删除对象属性 app.$delete(app.obj, "newKey"); // 如果是采用 直接 delete 会导致内存溢出【 reactive 还存在 】
/*这里直接引入官网的示例*/
// app.$nextTick
methods: {
// ...
example: function () {
// 修改数据
this.message = 'changed'
// DOM 还没有更新
this.$nextTick(function () {
// DOM 现在更新了
this.doSomethingElse()
})
}
}
// 先执行了 init 【 new Vue 之后会自动调用 】先去执行了 beforeCreate
beforeCreate(){
// 这里只是事件已经初始化好了,数据部分还没有
// 这里不要修改数据,因为还没有 reactive
}
// 然后在 init 的注入和 reactive 时会调用 created
created(){}
beforeMount(){}
// render function 会在这之间执行
render(){}
// render 出错的时候,但是只捕获本组件的错误,子组件中的错误不会被捕获
renderError(){
// 一般只用于开发环境
}
mounted(){}
beforeUpdate(){}
updated(){}
/*
// 一般在 keep-alive 组件的活跃状态和非活跃状态时触发
*/
activated(){}
deactivated(){}
/*
// 一般在需要销毁一个组件实例的时候使用
app.$destroy()
*/
beforeDestroy(){}
destroyed(){}
// 会向上冒泡,捕获错误,也可以用于正式环境
errorCaptured(){}
new Vue({
// 可以直接使用 js 的内置对象和方法
template: `
{{Date.now()}}
{{a.join('')}}
{{fn()}}
`,
data: {
a: [1, 2, 3],
},
methods: {
fn(arr) {
// 其实更好的是通过 computed
return arr.join("");
},
},
});
computed 是经过缓存处理的,针对于计算量比较大的操作而言比较合适
computed:{
val(){
return ...
}
}
// or
computed:{
val:{
get(){
return ...
}
// 当然这是不推荐的方式【computed中最好只用于处理数据之后返回,而不要在这里进行数据的变更】
set(newVal){
//...
}
}
}
主要的运用场景是,监听到某个数据的变化,然后执行某个指定的操作(比如 ajax 等)
watch: {
// 这是 data 中的数据项
// 在一开始的时候,数据没有变化,这里也就不执行,等待数据变化才会执行
input(newVal, oldVal) {
console.log("handle:", newVal, oldVal);
},
},
// 当然上面的 watch 只是一种简写形式,其实它的内部也会编译成为下面中形式
watch: {
// 这是 data 中的数据项
input: {
handler(newVal, oldVal) {
console.log("handle:", newVal, oldVal);
},
// 是否立即执行 handler ,如果没有此项就表明需要等待 input 数据项变化的时候才执行
immediate: true,
}
},
// 监听对象属性的变化
watch: {
obj: {
handler(newVal, oldVal) {
console.log("handle:", newVal, oldVal);
},
// 当然这个配置的开销会比较大,毕竟要去监听对象中每一层每一个属性的变化
deep: true, // 是否深度监听
}
},
// 如果只想监听对象中某一个属性的变化
watch: {
// 比如这里只监听 obj 对象中的 a 属性的变化,这样的性能开销比较小
'obj.a': {
handler(newVal, oldVal) {
console.log("handle:", newVal, oldVal);
},
}
},
new Vue({
template: `
`,
/*
// 给变量前面加一点其他的信息
template: `
`,
*/
/*
// 其实更好的运用场景是根据用户的权限动态的展示界面功能
template: `
level-1
level-2
level-3
`,
*/
/*
data:{
arr:[1,2,3],
obj:{
a:"111",
b:"222",
c:"333",
}
}
template: `
`,
//
data: {
arr: [1, 3, 4],
picked: "a",
},
// 这样只有a 和 c 会被选中,:value 和 value 的区别是 后者是单纯的字符串,前者会解析数值。
template:`
a
b
c
单选:d
e
`
*/
//修饰符
/*
只有在失去焦点时才会触发 onchange
*/
/*
只会数据绑定的内容只会执行一次,再有数据变化不会更新视图
{{msg}}
*/
});
因为组件可能会复用,如果复用组件,那么多个组件就会使用同一个数据对象,造成污染,所以需要在组件中 data 以 function 的形式存在
let app = new Vue({
components: {
T: {
// props: ["test", "str"], // 这是一种不太严谨的写法
props: {
test: {
type: Boolean,
required: true,
default: true,
/*
其实 required: true 之后default也可以直接不要,如果需要default 而且如果是一个对象那么最好也是直接用函数形式返回一个对象,避免组件复用数据污染
default(){
return {}
}
*/
},
str: String,
other: {
validator(value) {
// ... 进行一波检测
// 如果符合
return true;
},
},
},
template: `{{str}}
`,
},
},
data: {
arr: [1, 3, 4],
picked: "a",
},
mounted() {
// 取出名称为 t1 的组件实例
console.log(this.$refs.t1);
},
template: `
00
1
`,
}).$mount(root);
const com1 = {
props: {},
template: "",
data() {},
};
const com2 = {
extends: com1,
data() {
return {};
},
methods: {},
};
new Vue({
components: {
com2: com2,
},
templates: ` `,
});
const com1 = {
template: `
`,
data() {
return {
val: "com1 Data",
};
},
};
new Vue({
data: {
val: "Vue Data",
},
components: {
com1: com1,
},
template: `
header
content
{{val}}
{{props.val}}-{{props.abc}}
`,
});
const com1 = {
template: `
`,
data() {
return {
val: "com1 Data",
};
},
};
new Vue({
data: {
val: "Vue Data",
},
components: {
com1: com1,
},
// template: `
//
//
// hello
//
// `,
// 上面的 template 会走下面的流程
// 而这里的 createElement 其实就是在创建虚拟 DOM,存储在内存中,
// 会跟真正的 DOM 结构进行对比,如果对比的结果是需要更新原来的DOM结构,
// 就会将 虚拟 DOM 转换成为真正的 DOM
render(createElement) {
return createElement(
"com1",
{
ref: "com1",
},
[
createElement(
"p",
{
slot: "test",
ref: "p1",
"slot-scope": "props",
},
"hello"
),
]
);
},
});