iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
1
Modern Web

Quasar CLI Framework 邪教:整合分散的前端技術和工具、常見的開發需求系列 第 27

第二十七天:UI切版 & 元件-按鈕元件、常用的表單元件

今天的內容

一、表單元件常用的屬性
二、按鈕元件:QBtn
三、文字輸入:QInput
四、核取方塊 (QCheckbox、QRadio)
五、下拉選單:(QSelect)
六、檔案選擇欄位:(QFile)
七、總結

一、表單元件常用的屬性

  • disable
    相當於原生HTML的disable
    無法進行欄位的資料選取和修改
    input-class的樣式也會稍微改變

  • readonly
    可以選取資料,但是無法修改資料
    不會改變input-class的樣式

  • v-model
    元件呈現的資料綁定

範例示意:
https://ithelp.ithome.com.tw/upload/images/20201016/201203318Mv1WUgbOS.png

<template>
    <div class="q-pa-md">
        <div class="q-gutter-y-md column" style="max-width: 300px">
          <q-input input-class="input rounded-borders" borderless v-model="text" hint="Readonly" :dense="dense" disable></q-input>

          <q-input input-class="input rounded-borders" borderless v-model="text" hint="Readonly" :dense="dense" readonly></q-input>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      text: '123'
    }
  }
}
</script>

<style lang="scss" scoped>
.input {
  padding: 0 7px;
  border: 1px solid #333;
}
</style>

二、按鈕元件:QBtn

用途相當廣泛的元件,經常用於

Quasar has a component called QBtn which is a button with a few extra useful features.
https://quasar.dev/vue-components/button#QBtn-API

https://ithelp.ithome.com.tw/upload/images/20201014/20120331KbVrSngcl8.png

  1. 超連結行為
<div class="q-pa-md q-gutter-sm">
    <q-btn unelevated type="a" href="start/pick-quasar-flavour" label="作為超連結" color="red-7"></q-btn>
</div>
  1. 前端路由行為
<div class="q-pa-md q-gutter-sm">
    <q-btn unelevated :to="{ name: 'routeName' }" label="前端路由行為" color="green-7"></q-btn>
</div>
  1. 資料操作行為
<div class="q-pa-md q-gutter-sm">
    <q-btn unelevated @click="someMethod" label="資料操作行為" color="blue-7"></q-btn>
</div>

QBtn的display是inline-block,預設寬度會根據內容改變
可以使用第二十一天談到的Flex Grid,設定寬度比例
以及第二十三天的class="full-width"設定與按鈕外的容器等寬

https://ithelp.ithome.com.tw/upload/images/20201014/20120331XdTU0Sjaj5.png

<div class="q-pa-md">
    <div class="row q-col-gutter-sm">
      <div class="col-12 col-sm-4">
        <q-btn class="full-width" unelevated type="a" href="start/pick-quasar-flavour" label="作為超連結" color="red-7"></q-btn>
      </div>
      
      <div class="col-12 col-sm-4">
        <q-btn class="full-width" unelevated label="前端路由行為" color="green-7"></q-btn>
      </div>
      
      <div class="col-12 col-sm-4">
        <q-btn class="full-width" unelevated @click="someMethod" label="資料操作行為" color="blue-7"></q-btn>
      </div>
    </div>
</div>

三、文字輸入:QInput

用於輸入文字的欄位

The QInput component is used to capture text input from the user. It uses v-model, similar to a regular input. It has support for errors and validation, and comes in a variety of styles, colors, and types.
https://quasar.dev/vue-components/input

除了一般的text,還包括了textarea和number
https://ithelp.ithome.com.tw/upload/images/20201012/20120331eku0i6oErs.png

<div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-input
        outlined
        v-model="phone"
        label="phone"
      ></q-input>
      <q-input
        type="number"       
        outlined
        v-model="number"
        label="number"
      ></q-input>
      <q-input
        type="textarea"       
        outlined
        v-model="textarea"
        label="textarea"
      ></q-input>
    </div>
</div>

Quasar提供了很多預設的樣式
如果不喜歡的話,可以使用borderless屬性,另外使用class與input-class自訂樣式
https://quasar.dev/vue-components/input

https://ithelp.ithome.com.tw/upload/images/20201012/2012033189ryqHFoLo.jpg

<template>
    <div id="q-app">
      <div class="q-pa-md">
        <div class="q-gutter-y-md column" style="width: 300px; max-width: 100%">
          <q-toolbar class="q-pa-sm bg-primary text-white rounded-borders">
            <q-btn round dense flat icon="menu" class="q-mr-xs"></q-btn>
            <q-avatar class="gt-xs">
              <img src="https://cdn.quasar.dev/logo/svg/quasar-logo.svg">
            </q-avatar>

            <q-space></q-space>

            <q-input dense borderless v-model="text" class="text-input" class="q-ml-md">
              <template v-slot:append>
                <q-icon v-if="text === ''" name="search"></q-icon>
                <q-icon v-else name="clear" class="cursor-pointer" @click="text = ''"></q-icon>
              </template>
            </q-input>
          </q-toolbar>
        </div>
      </div>
    </div>
</template>

<script>
export default {
  data () {
    return {
      text: ''
    }
  }
}
</script>

<style lang="scss" scoped>
.text-input {
  margin: 3px 12px;
  padding: 5px;
  background: white;
  border-radius: 10px;
}
</style>

QInput 前後可以透過<template v-slot:append>加入ICON

https://ithelp.ithome.com.tw/upload/images/20201012/20120331DI6wevbBlr.jpg

 <q-input outlined bottom-slots v-model="text" label="Label" counter :dense="dense">
        <template v-slot:prepend>
          <q-icon name="place" />
        </template>
        <template v-slot:append>
          <q-icon name="close" @click="text = ''" class="cursor-pointer" />
        </template>
 </q-input>

「clear屬性」自帶清除內容的功能

<q-input
    clearable
    clear-icon="close"
    outlined
    v-model="text"
    label="Label"
/>

「mask屬性」可以用於特定格式的文字輸入

<div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-input
        outlined
        v-model="phone"
        label="phone"
        mask="####-### ###"
        fill-mask="#"
      ></q-input>
    </div>
</div>

搭配QForm,可以做簡單的格式校驗
https://quasar.dev/vue-components/form

<template>
  <div class="q-pa-md" style="max-width: 400px">

    <q-form
      @submit="onSubmit"
      @reset="onReset"
      class="q-gutter-md"
    >
      <q-input
        filled
        v-model="name"
        label="Your name *"
        hint="Name and surname"
        lazy-rules
        :rules="[ val => val && val.length > 0 || 'Please type something']"
      />

      <q-input
        filled
        type="number"
        v-model="age"
        label="Your age *"
        lazy-rules
        :rules="[
          val => val !== null && val !== '' || 'Please type your age',
          val => val > 0 && val < 100 || 'Please type a real age'
        ]"
      />

      <q-toggle v-model="accept" label="I accept the license and terms" />

      <div>
        <q-btn label="Submit" type="submit" color="primary"/>
        <q-btn label="Reset" type="reset" color="primary" flat class="q-ml-sm" />
      </div>
    </q-form>

  </div>
</template>

<script>
export default {
  data () {
    return {
      name: null,
      age: null,
      accept: false
    }
  },
  methods: {
    onSubmit () {
      if (this.accept !== true) {
        this.$q.notify({
          color: 'red-5',
          textColor: 'white',
          icon: 'warning',
          message: 'You need to accept the license and terms first'
        })
      }
      else {
        this.$q.notify({
          color: 'green-4',
          textColor: 'white',
          icon: 'cloud_done',
          message: 'Submitted'
        })
      }
    },
    onReset () {
      this.name = null
      this.age = null
      this.accept = false
    }
  }
}
</script>

四、核取方塊 (QCheckbox、QRadio)

(一) 多選核取方塊: QCheckbox

常用於某組資料的多選
或者類似加入會員的同意條款選項

The QCheckbox component is another basic element for user input. You can use this to supply a way for the user to toggle an option.
https://quasar.dev/vue-components/checkbox

多選的v-model要指向同一個data陣列變數
https://ithelp.ithome.com.tw/upload/images/20201012/20120331sjSlAUJbTK.png

<template>
  <div class="q-pa-md">
    <div class="q-gutter-sm">
      <q-checkbox v-model="selection" val="teal" label="Teal" color="teal" />
      <q-checkbox v-model="selection" val="orange" label="Orange" color="orange" />
      <q-checkbox v-model="selection" val="red" label="Red" color="red" />
      <q-checkbox v-model="selection" val="cyan" label="Cyan" color="cyan" />
    </div>

    <div class="q-px-sm">
      The model data: <strong>{{ selection }}</strong>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      selection: [ 'teal', 'red' ]
    }
  }
}
</script>

單一選項的勾選狀態,data變數的值為true或false

<template>
  <div class="q-pa-md">
    <div class="q-gutter-sm">
      <q-checkbox
        v-model="customModel"
        color="secondary"
        label="Do you agree with the terms & conditions?"
      ></q-checkbox>
    </div>

    <div class="q-px-sm">
      The model data: <strong>'{{ customModel }}'</strong>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      customModel: false
    }
  }
}
</script>

(二) 單選選取方塊:QRadio

相對於Checkbox,用於某組資料的單選

The QRadio component is another basic element for user input. You can use this to supply a way for the user to pick an option from multiple choices.

v-model要指向同一個data變數
https://ithelp.ithome.com.tw/upload/images/20201012/20120331E9htCMoaIp.png

<template>
  <div class="q-pa-md">
    <div class="q-gutter-sm">
      <q-radio v-model="color" val="teal" label="Teal" color="teal" />
      <q-radio v-model="color" val="orange" label="Orange" color="orange" />
      <q-radio v-model="color" val="red" label="Red" color="red" />
      <q-radio v-model="color" val="cyan" label="Cyan" color="cyan" />
    </div>
    <div class="q-gutter-sm">
      <q-radio keep-color v-model="color" val="teal" label="Teal" color="teal" />
      <q-radio keep-color v-model="color" val="orange" label="Orange" color="orange" />
      <q-radio keep-color v-model="color" val="red" label="Red" color="red" />
      <q-radio keep-color v-model="color" val="cyan" label="Cyan" color="cyan" />
    </div>
    <div class="q-px-sm q-mt-sm">
      Your selection is: <strong>{{ color }}</strong>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      color: 'cyan'
    }
  }
}
</script>

五、下拉選單:QSelect

具有強大篩選功能的單選或下拉選單

The QSelect component has two types of selection: single or multiple. This component opens up a menu for the selection list and action. A filter can also be used for longer lists.
https://quasar.dev/vue-components/select

其中QSelect的選單選項格式允許:

  1. String
<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select filled v-model="model" :options="options" label="Standard" />
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      model: null,
      options: [
        'Google', 'Facebook', 'Twitter', 'Apple', 'Oracle'
      ]
    }
  }
}
</script>
  1. Object
<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select filled v-model="model" :options="options" label="Standard" />
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      model: null,
      options: [
        {
          label: 'Google',
          value: 'Google',
          description: 'Search engine',
          category: '1'
        },
        {
          label: 'Facebook',
          value: 'Facebook',
          description: 'Social media',
          category: '1'
        },
        {
          label: 'Twitter',
          value: 'Twitter',
          description: 'Quick updates',
          category: '2'
        },
        {
          label: 'Apple',
          value: 'Apple',
          description: 'iStuff',
          category: '2'
        },
        {
          label: 'Oracle',
          value: 'Oracle',
          disable: true,
          description: 'Databases',
          category: '3'
        }
      ]
    }
  }
}
</script>

要注意的是
如果選項是JSON格式
至少要包含「label」和「value」
label是顯示在QSelect上面的文字,value是代表這個選項的值
此時v-model預設的格式,會是整個選項的JSON格式

https://ithelp.ithome.com.tw/upload/images/20201013/20120331zoD935vZxo.png

{ label: 'Test', value: 0  }

如果你希望v-model的格式,是JSON選項的value,在QSelect顯示label
使用emit-value + map-options 屬性

https://ithelp.ithome.com.tw/upload/images/20201013/20120331ZkNuYER5kB.png

<q-select
    filled
    v-model="model"
    :options="options"
    label="Standard"
    emit-value
    map-options
/>

若要使用QSelect的篩選功能
需要設定「@filter」、「use-input」、「hide-selected」

<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        v-model="model"
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        :options="options"
        @filter="filterFn"
        hint="Basic filtering"
        style="width: 250px; padding-bottom: 32px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

<script>
const stringOptions = [
  'Google', 'Facebook', 'Twitter', 'Apple', 'Oracle'
]
export default {
  data () {
    return {
      model: null,
      options: stringOptions
    }
  },
  methods: {
    filterFn (val, update, abort) {
      update(() => {
        const needle = val.toLowerCase()
        this.options = stringOptions.filter(v => v.toLowerCase().indexOf(needle) > -1)
      })
    }
  }
}
</script>

六、檔案選擇欄位:QFile

有寫過檔案上傳的人應該知道
\原生的type=file,是不能使用v-model

QInput也是,不能使用v-model

Do NOT use a v-model when QInput is of type="file". Browser security policy does not allow a value to be set to such an input. As a result, you can only read it (attach an @input event), but not write it.
https://quasar.dev/vue-components/input

<template>
  <q-page class="flex flex-center q-gutter-md">
    <div>
      <q-input type="file" @change="selectData" borderless></q-input>
      <q-img :src="dataUri" v-show="dataUri !== null" width="300px"></q-img>
    </div>
  </q-page>
</template>

<script>
export default {
  name: 'PageIndex',
  
  data () {
    return {
      file: null,
      dataUri: null
    }
  },
  methods: {
    selectData (e) {
      const reader = new FileReader()

      this.file = e.target.files[0]

      reader.readAsDataURL(this.file)
      reader.onload = (e) => {
        this.dataUri = e.target.result
      }
    }
  }
}
</script>

你可使用QFile代替
QFile本身包含了@change => data 這段過程

QFile is a component which handles the user interaction for picking file(s).
https://quasar.dev/vue-components/file-picker

<template>
  <q-page class="flex flex-center q-gutter-md">
    <div style="width: 300px;">
      <q-file stack-label="選擇檔案" label-color="white" input-class="text-white" class="bg-grey-9 q-pa-sm" borderless v-model="file" @input="selectData"></q-file>
      <q-img :src="dataUri" v-show="dataUri !== null" width="300px"></q-img>
    </div>
  </q-page>
</template>

<script>
export default {
  name: 'PageIndex',
  
  data () {
    return {
      file: null,
      dataUri: null
    }
  },
  methods: {
    selectData (file) {
      const reader = new FileReader()

      this.file = file

      reader.readAsDataURL(this.file)
      reader.onload = (e) => {
        this.dataUri = e.target.result
      }
    }
  }
}
</script>

七、總結

今天大致介紹了比較常用表單元件
如果對其他的元件有興趣,可以參考Quasar的官方元件
明天接著介紹經常與表單搭配使用的Dialog


上一篇
第二十六天:UI切版 & 元件-圖文資訊元件、ICON字型 & SVG、通知訊息元件
下一篇
第二十八天:UI切版 & 元件-清單表格、彈出視窗
系列文
Quasar CLI Framework 邪教:整合分散的前端技術和工具、常見的開發需求31

尚未有邦友留言

立即登入留言