Vue 基础应用

VUE 实例

在我们使用 vue 之前我们需要事先得到 一个 vue 实例对象,我们需要传递一个对象用于描述你的 vue 实例。

const app = new Vue({});

DOM 相关

  • 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 是经过缓存处理的,针对于计算量比较大的操作而言比较合适

computed:{
  val(){
    return ...
  }
}
// or
computed:{
  val:{
    get(){
      return ...
    }
    // 当然这是不推荐的方式【computed中最好只用于处理数据之后返回,而不要在这里进行数据的变更】
    set(newVal){
      //...
    }
  }
}

watch

主要的运用场景是,监听到某个数据的变化,然后执行某个指定的操作(比如 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

    因为组件可能会复用,如果复用组件,那么多个组件就会使用同一个数据对象,造成污染,所以需要在组件中 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}}

`
, });

render function

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" ), ] ); }, });

你可能感兴趣的:(vue,课程体系重难点)