linche0859
1/5/2020 - 4:19 PM

JSX

Install

npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props

.babelrc不用加入

{
  "presets": ["@vue/babel-preset-jsx"]
}

Component

template改由render function產生

<script>
const ChildComponent = {
  // 不使用生命週期
  functional: true,
  props: {
    name: String,
    age: Number
  },
  render(createElement, { props }) {
    return (
      <div class="child-jsx">
        <h3>{props.name} - {props.age}</h3>
      </div>
    )
  }
}
export default {
  data() {
    return {
      list: [
        { name: 'alex', age: 18 },
        { name: 'john', age: 16 }
      ]
    }
  },
  render() {
    return (
      <section>
        {
          this.list.map(o =>
            <ChildComponent key={o.name} {...{ props: o }} />
          )
        }
      </section>
    )
  }
}
</script>

functional event

const ChildComponent = ({ props, listeners }) => (
  <div class="child-jsx">
    <h2 onClick={listeners.pipi}>hi {props.name}</h2>
  </div>
);
/*
以上寫法等同於以下寫法
const ChildComponent = {
  functional: true,
  render(h, { props, listeners }) {
    return (
      <div class="child-jsx">
        <h2 onClick={listeners.pipi}>hi {props.name}</h2>
      </div>
    );
  },
};
*/

export default {
  methods: {
    click() {
      console.log("click");
    }
  },
  render() {
    return (
      <section>
        <ChildComponent name="milkmidi" onPipi={this.click} />
      </section>
    );
  }
};

v-model

export default {
  data() {
      checkboxs: [{ name: 'vue' }, { name: 'react' }, { name: 'angular' }],
      checkedName: []
    }
  },
  render() {
    return (
      <section>
        {this.checkboxs.map(checkbox => {
          return (
            <div style="display: inline-block;">
              <input
                type="checkbox"
                id={checkbox.name}
                value={checkbox.name}
                v-model={this.checkedName}
              />
              <label for={checkbox.name}>{checkbox.name}</label>
            </div>
          )
        })}
      </section>
    )
  }
}

Conditional Rendering

babel-plugin-jsx-vue-functional會檢查是不是有 html tag,有才會做轉換,沒有就當一般的 function

const PermissionComponent = {
  functional: true,
  render(h, { props, slots }) {
    const { permissinCode } = props;
    if (permissinCode === 0) return null;
    return slots().default;
  }
};

export default {
  data() {
    return {
      permissinCode: 1
    };
  },
  render() {
    return (
      <section>
        <PermissionComponent permissinCode={this.permissinCode}>
          <h2>{`PermissionCode${this.permissinCode}`}</h2>
        </PermissionComponent>
      </section>
    );
  }
};

Slot & Event

componetn用法

export default {
  render: function() {
    return (
      <section>
        <div
          // normal attributes or component props.
          id="foo"
          // DOM properties are prefixed with `domProps`
          // 寫入div的text content
          domPropsInnerHTML="bar"
          // event listeners are prefixed with `on` or `nativeOn`
          onClick={this.clickHandler}
          // nativeOnClick={this.nativeClickHandler}

          // other special top-level properties
          class={{ foo: true, bar: false }}
          style={{ color: "red", fontSize: "14px" }}
          key="key"
          // assign the `ref` is used on elements/components with v-for
          ref="ref"
        ></div>
      </section>
    );
  }
};

component用法

const StyleCompomemt = {
  functional: true,
  props: ["id"],
  render(h, context) {
    return (
      <div onClick={context.data.nativeOnClick}>{context.slots().footer}</div>
    );
  }
};

export default {
  methods: {
    clickHandler() {
      console.log("clickHandler");
    },
    nativeClickHandler() {
      this.count++;
      console.log("nativeClickHandler");
    }
  },
  render() {
    return (
      <section>
        <StyleCompomemt {...data}>
          <div slot="header">This is header</div>
          <div>This is main</div>
          <div slot="footer">This is footer</div>
        </StyleCompomemt>
      </section>
    );
  }
};