mirror of
https://github.com/Hopiu/vue-material.git
synced 2026-05-03 04:54:43 +00:00
Create switches and remove label with empty slot
This commit is contained in:
parent
310baef919
commit
32d58d7bcf
13 changed files with 306 additions and 8 deletions
|
|
@ -16,7 +16,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"autosize": "^3.0.17",
|
||||
"scopedQuerySelectorShim": "github:lazd/scopedQuerySelectorShim"
|
||||
"scopedQuerySelectorShim": "github:lazd/scopedQuerySelectorShim",
|
||||
"vue-touch": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.11.4",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ $checkbox-ripple-size: 48px;
|
|||
.md-checkbox-container {
|
||||
width: $checkbox-size;
|
||||
height: $checkbox-size;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
border-radius: 2px;
|
||||
border: 2px solid rgba(#000, .54);
|
||||
|
|
@ -59,6 +58,7 @@ $checkbox-ripple-size: 48px;
|
|||
|
||||
.md-checkbox-label {
|
||||
height: $checkbox-size;
|
||||
padding-left: 8px;
|
||||
line-height: $checkbox-size;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div class="md-checkbox" :class="classes">
|
||||
<div class="md-checkbox-container" @mousedown="toggleCheck" v-md-ink-ripple="disabled">
|
||||
<div class="md-checkbox-container" @click="toggleCheck" v-md-ink-ripple="disabled">
|
||||
<input type="checkbox" v-model="model" :name="name" :id="id" :disabled="disabled" :value="value">
|
||||
</div>
|
||||
|
||||
<label :for="id || name" class="md-checkbox-label">
|
||||
<label :for="id || name" class="md-checkbox-label" v-if="hasSlot">
|
||||
<slot></slot>
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -24,6 +24,11 @@
|
|||
id: String,
|
||||
disabled: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasSlot: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
classes() {
|
||||
return {
|
||||
|
|
@ -40,7 +45,7 @@
|
|||
}
|
||||
},
|
||||
ready() {
|
||||
|
||||
this.hasSlot = this.$el.querySelector('label').innerHTML.trim() !== '';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
0
src/components/mdInputContainer/base.js
Normal file
0
src/components/mdInputContainer/base.js
Normal file
|
|
@ -12,7 +12,6 @@ $radio-ripple-size: 48px;
|
|||
.md-radio-container {
|
||||
width: $radio-size;
|
||||
height: $radio-size;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(#000, .54);
|
||||
|
|
@ -57,6 +56,7 @@ $radio-ripple-size: 48px;
|
|||
|
||||
.md-radio-label {
|
||||
height: $radio-size;
|
||||
padding-left: 8px;
|
||||
line-height: $radio-size;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div class="md-radio" :class="classes">
|
||||
<div class="md-radio-container" @mousedown="toggleCheck" v-md-ink-ripple="disabled">
|
||||
<div class="md-radio-container" @click="toggleCheck" v-md-ink-ripple="disabled">
|
||||
<input type="radio" v-model="model" :name="name" :id="id" :disabled="disabled" :value="value">
|
||||
</div>
|
||||
|
||||
<label :for="id || name" class="md-radio-label">
|
||||
<label :for="id || name" class="md-radio-label" v-if="hasSlot">
|
||||
<slot></slot>
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -27,6 +27,11 @@
|
|||
id: String,
|
||||
disabled: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasSlot: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
classes() {
|
||||
return {
|
||||
|
|
@ -41,6 +46,9 @@
|
|||
this.model = this.value;
|
||||
}
|
||||
}
|
||||
},
|
||||
ready() {
|
||||
this.hasSlot = this.$el.querySelector('label').innerHTML.trim() !== '';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
14
src/components/mdSwitch/index.js
Normal file
14
src/components/mdSwitch/index.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import VueTouch from 'vue-touch';
|
||||
import mdSwitch from './mdSwitch.vue';
|
||||
import mdSwitchTheme from './mdSwitch.theme';
|
||||
|
||||
export default function install(Vue) {
|
||||
Vue.use(VueTouch);
|
||||
VueTouch.config.pan = {
|
||||
threshold: 1
|
||||
};
|
||||
|
||||
Vue.component('md-switch', Vue.extend(mdSwitch));
|
||||
|
||||
window.VueMaterial.styles.push(mdSwitchTheme);
|
||||
}
|
||||
76
src/components/mdSwitch/mdSwitch.scss
Normal file
76
src/components/mdSwitch/mdSwitch.scss
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
@import '../../core/variables.scss';
|
||||
|
||||
$switch-width: 34px;
|
||||
$switch-height: 14px;
|
||||
$switch-thumb-size: 20px;
|
||||
$switch-ripple-size: 48px;
|
||||
|
||||
.md-switch {
|
||||
width: auto;
|
||||
margin: 16px 8px 16px 0;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
|
||||
.md-switch-container {
|
||||
width: $switch-width;
|
||||
height: $switch-height;
|
||||
position: relative;
|
||||
border-radius: $switch-height;
|
||||
transition: $swift-ease-out;
|
||||
background-color: rgba(#000, .38);
|
||||
|
||||
.md-switch-thumb {
|
||||
width: $switch-thumb-size;
|
||||
height: $switch-thumb-size;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
cursor: grab;
|
||||
background-color: #fafafa;
|
||||
border-radius: 50%;
|
||||
box-shadow: $material-shadow-1dp;
|
||||
transition: $swift-linear;
|
||||
}
|
||||
|
||||
input {
|
||||
position: absolute;
|
||||
left: -999em;
|
||||
}
|
||||
|
||||
.md-ink-ripple {
|
||||
top: -16px;
|
||||
right: -16px;
|
||||
bottom: -16px;
|
||||
left: -16px;
|
||||
border-radius: 50%;
|
||||
color: rgba(#000, .54);
|
||||
|
||||
.md-ripple {
|
||||
width: $switch-ripple-size !important;
|
||||
height: $switch-ripple-size !important;
|
||||
top: 0 !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.md-switch-label {
|
||||
height: $switch-height;
|
||||
padding-left: 8px;
|
||||
line-height: $switch-height;
|
||||
}
|
||||
}
|
||||
|
||||
.md-switch.md-dragging {
|
||||
.md-switch-thumb {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
.md-switch.md-disabled {
|
||||
.md-switch-thumb {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
29
src/components/mdSwitch/mdSwitch.theme
Normal file
29
src/components/mdSwitch/mdSwitch.theme
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
.THEME_NAME {
|
||||
.md-switch,
|
||||
&.md-switch {
|
||||
&.md-checked {
|
||||
.md-switch-container,
|
||||
.md-switch-thumb {
|
||||
background-color: ACCENT-COLOR;
|
||||
}
|
||||
|
||||
.md-ink-ripple {
|
||||
color: ACCENT-COLOR;
|
||||
}
|
||||
|
||||
.md-ripple {
|
||||
opacity: .38;
|
||||
}
|
||||
}
|
||||
|
||||
&.md-disabled {
|
||||
.md-switch-container {
|
||||
background-color: rgba(#000, .12);
|
||||
}
|
||||
|
||||
.md-switch-thumb {
|
||||
background-color: #bdbdbd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
108
src/components/mdSwitch/mdSwitch.vue
Normal file
108
src/components/mdSwitch/mdSwitch.vue
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<div class="md-switch" :class="classes">
|
||||
<div class="md-switch-container" @click="onClick">
|
||||
<div class="md-switch-thumb" :style="styles" v-md-ink-ripple="disabled" v-touch:panstart="onDragStart" v-touch:panmove="onDrag" v-touch:panend="onDragEnd" v-touch-options:pan="{ direction: 'horizontal' }">
|
||||
<input type="checkbox" v-model="model" :name="name" :id="id" :disabled="disabled" :value="value">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label :for="id || name" class="md-switch-label" v-if="hasSlot">
|
||||
<slot></slot>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" src="./mdSwitch.scss"></style>
|
||||
|
||||
<script>
|
||||
let dragFrame;
|
||||
let fullThreshold = 75;
|
||||
let initialThreshold = '-1px';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
model: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
twoWay: true
|
||||
},
|
||||
name: String,
|
||||
id: String,
|
||||
disabled: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasSlot: true,
|
||||
leftPos: initialThreshold,
|
||||
percent: 0,
|
||||
dragging: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
classes() {
|
||||
return {
|
||||
'md-checked': Boolean(this.model),
|
||||
'md-disabled': this.disabled,
|
||||
'md-dragging': this.dragging
|
||||
};
|
||||
},
|
||||
styles() {
|
||||
return {
|
||||
transform: `translate3D(${this.leftPos}, -50%, 0)`
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
model() {
|
||||
this.leftPos = this.model ? fullThreshold + '%' : initialThreshold;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
if (!this.disabled && !this.dragging) {
|
||||
this.model = !this.model;
|
||||
}
|
||||
},
|
||||
onDragStart() {
|
||||
if (!this.disabled) {
|
||||
this.dragging = true;
|
||||
}
|
||||
},
|
||||
onDrag(event) {
|
||||
if (!this.disabled) {
|
||||
dragFrame = requestAnimationFrame(() => {
|
||||
let percent = 0;
|
||||
|
||||
if (this.model) {
|
||||
percent = 20;
|
||||
}
|
||||
|
||||
percent = Math.round((event.deltaX + percent) * 100 / 34);
|
||||
|
||||
if (percent >= 0 && percent <= fullThreshold) {
|
||||
this.percent = percent;
|
||||
this.leftPos = percent + '%';
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
onDragEnd() {
|
||||
if (!this.disabled) {
|
||||
setTimeout(() => {
|
||||
this.dragging = false;
|
||||
}, 50);
|
||||
|
||||
this.model = this.percent >= fullThreshold / 2;
|
||||
this.leftPos = this.model ? fullThreshold + '%' : initialThreshold;
|
||||
}
|
||||
}
|
||||
},
|
||||
ready() {
|
||||
this.hasSlot = this.$el.querySelector('label').innerHTML.trim() !== '';
|
||||
this.leftPos = this.model ? fullThreshold + '%' : initialThreshold;
|
||||
},
|
||||
destroyed() {
|
||||
cancelAnimationFrame(dragFrame);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
50
src/docs/pages/Switch.vue
Normal file
50
src/docs/pages/Switch.vue
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<section>
|
||||
<h2 class="title">Switch</h2>
|
||||
|
||||
<div>
|
||||
<md-switch :model.sync="checked0" id="my-test0" name="my-test0"></md-switch>
|
||||
</div>
|
||||
|
||||
<div v-md-theme="'indigo'">
|
||||
<md-switch :model.sync="checked1" id="my-test1" name="my-test1"></md-switch>
|
||||
</div>
|
||||
|
||||
<div v-md-theme="'blue'">
|
||||
<md-switch :model.sync="checked2" id="my-test2" name="my-test2"></md-switch>
|
||||
</div>
|
||||
|
||||
<div v-md-theme="'orange'">
|
||||
<md-switch :model.sync="checked3" id="my-test3" name="my-test3"></md-switch>
|
||||
</div>
|
||||
|
||||
<div v-md-theme="'bottom-bar'">
|
||||
<md-switch :model.sync="checked4" id="my-test4" name="my-test4"></md-switch>
|
||||
</div>
|
||||
|
||||
<div v-md-theme="'bottom-bar'">
|
||||
<md-switch :model.sync="checked5" id="my-test5" name="my-test5" disabled></md-switch>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
section {
|
||||
padding: 0 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
checked0: true,
|
||||
checked1: true,
|
||||
checked2: true,
|
||||
checked3: true,
|
||||
checked4: true,
|
||||
checked5: true
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -5,6 +5,7 @@ import Buttons from './pages/Buttons';
|
|||
import ButtonToggle from './pages/ButtonToggle';
|
||||
import Checkbox from './pages/Checkbox';
|
||||
import Radio from './pages/Radio';
|
||||
import Switch from './pages/Switch';
|
||||
import Divider from './pages/Divider';
|
||||
import Icon from './pages/Icon';
|
||||
import Input from './pages/Input';
|
||||
|
|
@ -41,6 +42,10 @@ const routes = {
|
|||
name: 'radio',
|
||||
component: Radio
|
||||
},
|
||||
'/switch': {
|
||||
name: 'switch',
|
||||
component: Switch
|
||||
},
|
||||
'/checkbox': {
|
||||
name: 'checkbox',
|
||||
component: Checkbox
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import MdButton from './components/mdButton';
|
|||
import MdButtonToggle from './components/mdButtonToggle';
|
||||
import MdCheckbox from './components/mdCheckbox';
|
||||
import mdRadio from './components/mdRadio';
|
||||
import mdSwitch from './components/mdSwitch';
|
||||
import MdDivider from './components/mdDivider';
|
||||
import MdIcon from './components/mdIcon';
|
||||
import MdInputContainer from './components/mdInputContainer';
|
||||
|
|
@ -23,6 +24,7 @@ let options = {
|
|||
MdButtonToggle,
|
||||
MdCheckbox,
|
||||
mdRadio,
|
||||
mdSwitch,
|
||||
MdDivider,
|
||||
MdIcon,
|
||||
MdInputContainer,
|
||||
|
|
|
|||
Loading…
Reference in a new issue