提交 ebd8a429 编写于 作者: K kevinluohuan

bugfix: using builtin components to check allowed tags

上级 d469f028
const fs = require('fs');
const path = require('path');
const config = require('../../config');
const Parser = require('cml-component-parser');
const parser = new Parser(null, config.getParserConfig().script);
let getCml = function () {
let _builtinCompsInfo = {
name: '', version: '', components: {}
};
function getBuiltinVersion() {
let packDir = config.getCurrentWorkspace() + '/node_modules/chameleon-ui-builtin';
let packageJsonFile = path.resolve(packDir, 'package.json');
if (fs.existsSync(packageJsonFile)) {
let fileRawContent = fs.readFileSync(packageJsonFile, 'utf8');
let jsonObj = JSON.parse(fileRawContent);
if (jsonObj.version && jsonObj.name) {
return {
name: jsonObj.name,
version: jsonObj.version
}
}
}
return null;
}
function isPackageUpdated() {
let pakcageInfo = getBuiltinVersion();
if (pakcageInfo && pakcageInfo.version === _builtinCompsInfo.version && pakcageInfo.name === _builtinCompsInfo.name) {
return false;
}
if (pakcageInfo) {
_builtinCompsInfo.name = pakcageInfo.name;
_builtinCompsInfo.version = pakcageInfo.version;
}
return true;
}
function getBuiltinComponents() {
let result = {};
let inDir = config.getCurrentWorkspace() + '/node_modules/chameleon-ui-builtin/components';
if (fs.existsSync(inDir)) {
Parser.flatEntrance(inDir).forEach(filterFile => {
let content = parser.resetPath(filterFile).getJsonResultsWithComponentName();
content && (result[content.name] = content.content);
});
}
return result;
_builtinCompsInfo.components = result;
return result;
}
module.exports = {
getCml
};
function getStoredComponentInfo() {
return _builtinCompsInfo.components;
}
module.exports.getCml = function () {
// check package version of built-in components
if (isPackageUpdated()) {
return getBuiltinComponents();
}
return getStoredComponentInfo();
}
module.exports.getBuiltinTags = function () {
let componentInfo = this.getCml();
return Object.keys(componentInfo);
}
......@@ -12,6 +12,10 @@ module.exports = {
cml: cmlWhiteList
}
module.exports.getFunctionalTags = function() {
return ['template', 'component', 'block', 'slot', 'view', 'text', 'cell', 'image'];
}
module.exports.getAllowedTags = function() {
return this.cml.tags;
}
......
......@@ -2,8 +2,6 @@
* tags: Technically, it only holds tags that are not a html tag.
*/
module.exports = {
// attrs: ['v-if','v-else','v-bind','v-cloak','v-for','v-html','v-model','v-on','v-once','v-pre','v-show','v-text'],
attrs: ['v-if', 'v-else', 'v-else-if', 'v-for', 'v-on', 'v-bind', 'v-html', 'v-show', 'v-model', 'v-pre', 'v-once', 'slot-scope', 'is'],
// tags: ['template','component','keep-alive','transition','transition-group']
attrs: ['v-if', 'v-else', 'v-else-if', 'v-for', 'v-on', 'v-bind', 'v-html', 'v-show', 'v-model', 'v-pre', 'v-once', 'slot-scope'],
tags: ['template', 'view', 'text', 'block', 'scroller', 'list', 'cell', 'image', 'switch', 'video', 'input', 'button', 'radio', 'checkbox', 'page', 'router-view', 'slot']
}
......@@ -68,7 +68,8 @@ function getLintOptions(params) {
options['attr-bans'] = whiteListConifg.getForbiddenAttrsByLang(params.lang);
options['tag-only-allowed-names'] = whiteListConifg
.getAllowedTags()
.getFunctionalTags()
.concat(builtinComponents.getBuiltinTags())
.concat(params.custimizedTags
.map((tag) => {
return tag.name;
......
......@@ -14,6 +14,9 @@ const path = require('path');
describe('cml', function() {
const projectRoot = path.resolve(__dirname, './template/docs/');
config.init(projectRoot);
describe('lint-json', function() {
it('json-standard', async function() {
const cmlPath = path.resolve(__dirname, './linter/cml/json/standard.cml');
......
<script cml-type="interface">
/*
定义一个inteface用于描述组件的属性和事件
1、 如果区分组件属性和事件?
通过类型来区分,事件为函数类型,属性为非函数类型
2、 如何定义组件属性
给interface添加同名的属性即可,指定类型
3、 如何定义组件事件
以事件名称为key值给interface定义属性,该属性是一个函数类型,返回值为void,
定义函数的第一个参数为自定义事件传递的detail对象类型
*/
//定义事件detail对象的参数
type inputEventDetail = {
value: String
}
type blurEventDetail = {}
type focusEventDetail = {}
type confirEventDetail = {}
interface InputInterface {
value: String,
type: String,
placeholder: String,
disabled: Boolean,
focus: Boolean,
maxlength: Number,
returnKeyType: String,
placerHolderColor: String,
cStyle: String,
maxValue: Number,
minValue: Number,
inputevent(eventDetail: inputEventDetail): void;
blurevent(eventDetail: inputEventDetail): void;
focusevent(eventDetail: void): void;
confirmevent(eventDetail: void): void;
input(eventDetail: inputEventDetail): void;
blur(eventDetail: inputEventDetail): void;
focus(eventDetail: void): void;
confirm(eventDetail: void): void;
}
</script>
<template>
<inputable
:value="value"
:type="type"
:placeholder="placeholder"
:disabled="disabled"
:maxlength="maxlength"
:focus="focus"
:returnKeyType="returnKeyType"
:placerHolderColor="placerHolderColor"
:pattern="typePattern"
:computedStyle="computedStyle"
template="input"
:maxValue="maxValue"
:minValue="minValue"
@input="inputEvent"
@blur="blurEvent"
@focus="focusEvent"
@keyup="keyupEvent"
></inputable>
</template>
<script>
/*
event: inputevent blurevent focusevent cconfirmevent
*/
class Input implements InputInterface {
data = {
defaultStyle: "line-height: normal;font-size: 16px; height: 40px;padding-left:10px; padding-right:10px; color: #000; border-width:1px; border-style:solid; border-color:#999;border-radius: 4px; text-align: left; background-color: #fff;",
typePattern: '*'
}
props = {
//类型
type: {
type: String,
default: 'text' //枚举值 text number password
},
value: {
type: String,
default: ''
},
//placerholder
placeholder: {
type: String,
default: ''
},
//是否禁用输入
disabled: {
type: Boolean,
default: false
},
//控制是否聚焦
focus: {
type: Boolean,
default: false
},
//最大长度
maxlength: {
type: Number,
default: 140
},
//右下角返回键类型
returnKeyType: { //枚举值 done search next go
type: String,
default: 'done'
},
placerHolderColor: {
type: String,
default: '#bebebe'
},
cStyle: {
type: String,
default: ''
},
maxValue: { //type=number 最大值
type: Number,
default: Infinity
},
minValue: { //type=number 最小值
type: Number,
default: -Infinity
}
}
computed = {
computedStyle() {
return this.defaultStyle + this.cStyle
}
}
methods = {
inputEvent(e) {
this.$cmlEmit('input', {
value: e.target.value || ''
});
this.$cmlEmit('inputevent', {
value: e.target.value || ''
});
},
blurEvent(e) {
window.scroll(0,0); // 键盘收起留白的bug
this.$cmlEmit('blur', {
value: e.target.value || ''
});
this.$cmlEmit('blurevent', {
value: e.target.value || ''
});
},
focusEvent(e) {
this.$cmlEmit('focus');
this.$cmlEmit('focusevent');
},
// support enter key event
keyupEvent (e) {
this.$cmlEmit('confirm')
this.$cmlEmit('confirmevent')
}
}
}
export default new Input();
</script>
<style scoped>
input::-webkit-input-placeholder {
line-height: normal;
}
</style>
<script cml-type="json">
{
"base": {
"usingComponents": {
"inputable": "../../assets/vue/inputable"
}
},
"web": {
"component": true
}
}
</script>
<template>
<input
value="{{value}}"
type="{{type}}"
placeholder="{{placeholder}}"
disabled="{{disabled}}"
maxlength="{{maxlength}}"
c-bind:input="inputEvent"
c-bind:blur="blurEvent"
c-bind:focus="focusEvent"
c-bind:confirm="confirmEvent"
ref="weexinput"
return-key-type="{{returnKeyType}}"
style="{{computedStyle}}"
/>
</template>
<script>
/*
event: inputevent blurevent focusevent cconfirmevent
*/
import {getValBetweenMaxAndMin} from '../../assets/js/utils/utils';
class Input implements InputInterface {
props = {
//input的内容
value: {
type: String,
default: ''
},
//input的类型
type: {
type: String,
default: 'text' //枚举值 text number password
},
//input的placerholder
placeholder: {
type: String,
default: ''
},
//是否禁用input输入
disabled: {
type: Boolean,
default: false
},
//控制input是否聚焦
focus: {
type: Boolean,
default: false
},
//最大长度
maxlength: {
type: Number,
default: 140
},
//右下角返回键类型
returnKeyType: { //枚举值 done search next go
type: String,
default: 'done'
},
placerHolderColor: {
type: String,
default: '#bebebe'
},
cStyle: {
type: String,
default: ''
},
maxValue: { //type=number 最大值
type: Number,
default: Infinity
},
minValue: { //type=number 最小值
type: Number,
default: -Infinity
}
}
data = {
defaultStyle: "font-size: 33cpx; height: 80cpx; line-height: 80cpx; padding-left:20cpx; padding-right:20cpx; color: #000; border-width:1px; border-style:solid; border-color:#999;border-radius: 8cpx; text-align: left; background-color: #fff;",
inputValue: ''
}
computed ={
computedStyle() {
let style = this.defaultStyle + this.cStyle;
if(style[style.length-1] !== ';') {
style +=';'
}
style += `placeholder-color: ${this.placerHolderColor};`
return style
},
isInputNumber () {
return this.type === 'number';
}
}
watch = {
focus: function(newVal, oldVal) {
this.changeFocus(newVal);
}
}
methods = {
changeFocus(focus) {
if(focus) {
this.$refs['weexinput'].focus();
} else {
this.$refs['weexinput'].blur();
}
},
inputEvent(e) {
let value = e.detail.value;
if (this.isInputNumber) {
value = getValBetweenMaxAndMin(value, this.maxValue, this.minValue);
this.inputValue = value;
}
this.$cmlEmit('input',{
value: value || ''
})
this.$cmlEmit('inputevent',{
value: value || ''
})
},
blurEvent(e) {
this.$cmlEmit('blur',{
value: this.inputValue || ''
});
this.$cmlEmit('blurevent',{
value: this.inputValue || ''
});
},
focusEvent(e) {
this.$cmlEmit('focus');
this.$cmlEmit('focusevent');
},
confirmEvent(e) {
this.$cmlEmit('confirm')
this.$cmlEmit('confirmevent')
}
}
mounted() {
this.changeFocus(this.focus);
}
}
export default new Input();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"weex": {
"component": true
}
}
</script>
\ No newline at end of file
<template>
<input
value="{{inputValue}}"
type="{{type}}"
placeholder="{{placeholder}}"
disabled="{{disabled}}"
maxlength="{{maxlength}}"
style="{{wxStyle}}"
c-bind:input="inputEvent"
c-bind:blur="blurEvent"
c-bind:focus="focusEvent"
c-bind:confirm="confirmEvent"
focus="{{focus}}"
confirm-type="{{returnKeyType}}"
placeholder-style="{{wxPlaceHolderStyle}}"
/>
</template>
<script>
import {getValBetweenMaxAndMin} from '../../assets/js/utils/utils';
class Input implements InputInterface {
props = {
value: {
type: String,
default: ''
},
//input的类型
type: {
type: String,
default: 'text' //枚举值 text number password
},
//input的placerholder
placeholder: {
type: String,
default: ''
},
//是否禁用input输入
disabled: {
type: Boolean,
default: false
},
//控制input是否聚焦
focus: {
type: Boolean,
default: false
},
//最大长度
maxlength: {
type: Number,
default: 140
},
//右下角返回键类型
returnKeyType: { //枚举值 done search next go
type: String,
default: 'done'
},
placerHolderColor: {
type: String,
default: '#bebebe'
},
cStyle: {
type: String,
default: ''
},
maxValue: { //type=number 最大值
type: Number,
default: Infinity
},
minValue: { //type=number 最小值
type: Number,
default: -Infinity
}
}
data = {
inputValue: "",
defaultStyle: "font-size: 33cpx; height: 80cpx; line-height: 80cpx; padding-left:20cpx; padding-right:20cpx; color: #000; border: 1px solid #999;border-radius: 8cpx; text-align: left; background-color: #fff;"
}
computed ={
wxPlaceHolderStyle() {
return `color: ${this.placerHolderColor};`
},
wxStyle() {
let style = this.defaultStyle + this.cStyle;
return style
},
isInputNumber () {
return this.type === 'number';
}
}
watch = {
focus: function(newVal, oldVal) {
},
value: function(newVal, oldVal) {
this.inputValue = newVal;
}
}
mounted() {
this.inputValue = this.value;
}
methods = {
inputEvent(e) {
let value = e.detail.value;
if (this.isInputNumber) {
value = getValBetweenMaxAndMin(value, this.maxValue, this.minValue);
}
this.$cmlEmit('input',{
value: value || ''
})
this.$cmlEmit('inputevent',{
value: value || ''
})
},
blurEvent(e) {
let value = e.detail.value;
if (this.isInputNumber) {
value = getValBetweenMaxAndMin(value, this.maxValue, this.minValue);
}
this.$cmlEmit('blurevent',{
value: value
});
this.$cmlEmit('blur',{
value: value
});
},
focusEvent(e) {
this.$cmlEmit('focusevent');
this.$cmlEmit('focus');
},
confirmEvent(e) {
this.$cmlEmit('confirmevent')
this.$cmlEmit('confirm')
}
}
}
export default new Input();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"wx": {
"component": true
}
}
</script>
\ No newline at end of file
<script cml-type="interface">
/*
定义一个inteface用于描述组件的属性和事件
1、 如果区分组件属性和事件?
通过类型来区分,事件为函数类型,属性为非函数类型
2、 如何定义组件属性
给interface添加同名的属性即可,指定类型
3、 如何定义组件事件
以事件名称为key值给interface定义属性,该属性是一个函数类型,返回值为void,
定义函数的第一个参数为自定义事件传递的detail对象类型
*/
//定义事件detail对象的参数
type scrollEventDetail = {
deltaX: Number,
deltaY: Number,
scrollHeight: Number,
scrollLeft: Number,
scrollTop: Number,
scrollWidth: Number
}
type scrolltobottomEventDetail = {
direction: String
}
interface ScrollerInterface {
cstyle: String,
bottomOffset: Number,
scrollDirection: String,
bounce: Boolean,
height: Number,
width: Number,
scrollTop: Number,
scrollLeft: Number,
onscroll(eventDetail: scrollEventDetail): void;
customscroll(eventDetail: scrollEventDetail): void;
scrolltobottom(eventDetail: scrolltobottomEventDetail): void;
}
</script>
<template>
<scrollable
:cstyle="cstyle"
:bottomOffset="bottomOffset"
:scrollDirection="scrollDirection"
:bounce="bounce"
:height="heightPx"
:width="widthPx"
template="scroller"
scrollTop="{{scrollTopPx}}"
scrollLeft="{{scrollLeftPx}}"
@onscroll= "scrollEvent"
@scrolltobottom = "scrolltobottomEvent"
>
<slot></slot>
</scrollable>
</template>
<script>
import {cpx2px} from '../../assets/js/utils/utils'
class Scroller implements ScrollerInterface {
props = {
bottomOffset: {
// 距底部/右边多远时(单位cpx),触发 scrollbottom 事件
type: Number,
default: 0
},
bounce: {
type: Boolean,
default: true
},
cstyle: {
type: String,
default: ''
},
scrollDirection: {
// 可选为 horizontal 或者 vertical,默认值为 vertical 。定义滚动的方向。
type: String,
default: 'vertical'
},
height: {
type: Number,
default: 0
},
width: {
type: Number,
default: 0
},
scrollTop: {
type: Number,
default: 0
},
scrollLeft: {
type: Number,
default: 0
}
}
computed = {
heightPx () {
if (this.height >= 0) {
return cpx2px(this.height);
}
return -1;
},
widthPx () {
if (this.width >= 0) {
return cpx2px(this.width);
}
return -1;
},
scrollTopPx () {
return cpx2px(this.scrollTop);
},
scrollLeftPx () {
return cpx2px(this.scrollLeft);
}
}
methods = {
scrollEvent (e) {
this.$cmlEmit('onscroll', e)
this.$cmlEmit('customscroll', e)
},
scrolltobottomEvent (e) {
this.$cmlEmit('scrolltobottom', e)
}
}
}
export default new Scroller();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"web": {
"component": true,
"usingComponents": {
"scrollable": "../../assets/vue/scrollable"
}
}
}
</script>
\ No newline at end of file
<template>
<scroller
ref="c-scroller"
style="{{wrapperStyle}}"
class="{{afterClass}}"
show-scrollbar="false"
scroll-direction="{{scrollDirection}}"
loadmoreoffset="{{bottomOffset}}"
offset-accuracy="10"
c-bind:loadmore="onBottom"
c-bind:scroll="onScroll"
>
<slot>
</slot>
</scroller>
</template>
<script>
import cml from 'chameleon-api'
const dom = weex.requireModule('dom')
class Scroller implements ScrollerInterface {
props = {
cstyle: {
type: String,
default: ''
},
bottomOffset: {
// 距底部/右边多远时(单位px),触发 scrolltolower 事件
type: Number,
default: 0
},
scrollDirection: {
// 可选为 horizontal 或者 vertical,默认值为 vertical 。定义滚动的方向。
type: String,
default: 'vertical'
},
bounce: {
type: Boolean,
default: true
},
//-1表示占用剩余高度或者宽度
height: {
type: Number,
default: 0
},
width: {
type: Number,
default: 0
},
scrollTop: {
type: Number,
default: 0
},
scrollLeft: {
type: Number,
default: 0
}
}
data = {
cmtStyle: ''
}
computed ={
wrapperStyle() {
if (this.scrollDirection === 'vertical') {
if (this.height >= 0) {
return `${this.cstyle};height:${this.height}cpx;`
} else if (this.cstyle && this.cstyle.indexOf('height') !== -1) {
return this.cstyle
}
} else {
if (this.width >= 0) {
return `${this.cstyle};width:${this.width}cpx;white-space:nowrap;`
} else if (this.cstyle && this.cstyle.indexOf('width') !== -1) {
return this.cstyle
}
}
// 没有传递的情况
return this.cmtStyle + this.cstyle;
},
afterClass() {
return this.scrollDirection === 'vertical'
? 'flex-column':
'flex-row'
}
}
watch = {
scrollTop (val) {
this.scrollTo(val)
},
scrollLeft (val) {
this.scrollTo(val)
}
}
methods = {
scrollTo (offset) {
let el = this.$refs['c-scroller'] && this.$refs['c-scroller'].children[0]
if (el) {
dom.scrollToElement(el, { offset: offset })
}
},
onScroll(e) {
let detail = e.detail;
detail.deltaX = detail.deltaX || 0;
detail.deltaY = detail.deltaY || 0;
this.$cmlEmit('onscroll', detail);
this.$cmlEmit('customscroll', detail)
},
onBottom(e) {
this.$cmlEmit('scrolltobottom', e.detail)
}
}
mounted () {
setTimeout(async() => {
if (this.scrollDirection === 'vertical' && !this.height) {
console.error('纵向滚动必须传递高度属性')
return
}
if (this.scrollDirection === 'horizontal' && !this.width) {
console.error('横向滚动必须传递宽度属性')
return
}
if (this.height === -1 || this.width === -1) {
let rectData = await cml.getRect(this.$refs['c-scroller'], this)
let windowRect = await cml.getSystemInfo()
if (this.scrollDirection === 'vertical') {
let height = windowRect.viewportHeight - rectData.top;
this.cmtStyle = `height:${height}cpx;`
} else {
let width = windowRect.viewportWidth - rectData.left
this.cmtStyle = `width:${width}cpx;white-space:nowrap;`
}
}
}, 200)
}
}
export default new Scroller();
</script>
<style scoped>
.flex-row {
flex-direction: row;
}
.flex-column {
flex-direction: column;
}
</style>
<script cml-type="json">
{
"weex": {
"component": true
}
}
</script>
<template>
<origin-scroll-view
scroll-x="{{ scrollDirection === 'horizontal' }}"
scroll-y="{{ scrollDirection === 'vertical' }}"
scroll-with-animation="true"
scroll-into-view="{{toView}}"
lower-threshold="{{bottomOffset+'rpx'}}"
enable-back-to-top="true"
bindscrolltolower="onBottom"
bindscroll="onScroll"
class="cml-scroller"
style="{{wrapperStyle}}"
scroll-top="{{scrollTopPx}}"
scroll-left="{{scrollLeftPx}}"
ref="c-scroller"
>
<slot></slot>
</origin-scroll-view>
</template>
<script>
import cml from 'chameleon-api'
class Scroller implements ScrollerInterface {
props = {
cstyle: {
type: String,
default: ''
},
bottomOffset: {
// 距底部/右边多远时(单位px),触发 scrolltolower 事件
type: Number,
default: 0
},
scrollDirection: {
// 可选为 horizontal 或者 vertical,默认值为 vertical 。定义滚动的方向。
type: String,
default: 'vertical'
},
bounce: {
type: Boolean,
default: true
},
height: {
type: Number,
default: 0
},
width: {
type: Number,
default: 0
},
scrollTop: {
type: Number,
default: 0
},
scrollLeft: {
type: Number,
default: 0
}
}
data = {
cmtStyle: ''
}
computed = {
wrapperStyle () {
if (this.scrollDirection === 'vertical') {
if (this.height >= 0) {
return `${this.cstyle};height:${this.height}rpx;`
}
} else {
if (this.width >= 0) {
return `${this.cstyle};width:${this.width}rpx;white-space:nowrap;`
}
}
// 没有传递的情况
return this.cmtStyle + this.cstyle;
},
scrollTopPx () {
// scroll-top仅支持px
return cml.cpx2px(this.scrollTop)
},
scrollLeftPx () {
return cml.cpx2px(this.scrollLeft)
}
}
methods = {
onScroll(e) {
let detail = e.detail;
detail.deltaX = detail.deltaX || 0;
detail.deltaY = detail.deltaY || 0;
Object.keys(detail).forEach((key) => {
detail[key] = cml.px2cpx(detail[key]);
})
this.$cmlEmit('onscroll', detail)
this.$cmlEmit('customscroll', detail)
},
onBottom(e) {
this.$cmlEmit('scrolltobottom', e.detail)
}
}
mounted () {
setTimeout(async() => {
if (this.scrollDirection === 'vertical' && !this.height) {
console.error('纵向滚动必须传递高度属性')
return
}
if (this.scrollDirection !== 'vertical' && !this.width) {
console.error('横向滚动必须传递宽度属性')
return
}
if (this.height === -1 || this.width === -1) {
let rectData = await cml.getRect(this.$refs['c-scroller'], this)
let windowRect = await cml.getSystemInfo()
if (this.scrollDirection === 'vertical') {
let height = windowRect.viewportHeight - rectData.top;
this.cmtStyle = `height:${height}cpx;`
} else {
let width = windowRect.viewportWidth - rectData.left
this.cmtStyle = `width:${width}cpx;white-space:nowrap;`
}
}
}, 200)
}
}
export default new Scroller();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"wx": {
"component": true
}
}
</script>
<script cml-type="interface">
//定义事件detail对象的参数
type inputEventDetail = {
value: String
}
interface TextareaInterface {
value: String,
placeholder: String,
disabled: Boolean,
focus: Boolean,
maxlength: Number,
returnKeyType: String,
placerHolderColor: String,
cStyle: String,
rows: Number,
inputevent(eventDetail: inputEventDetail): void;
blurevent(eventDetail: void): void;
focusevent(eventDetail: void): void;
confirmevent(eventDetail: void): void;
input(eventDetail: inputEventDetail): void;
blur(eventDetail: void): void;
focus(eventDetail: void): void;
confirm(eventDetail: void): void;
}
</script>
<template>
<inputable
:value="value"
:placeholder="placeholder"
:disabled="disabled"
:maxlength="maxlength"
:rows="rows"
:focus="focus"
:returnKeyType="returnKeyType"
:placerHolderColor="placerHolderColor"
:computedStyle="computedStyle"
template="textarea"
@input="inputEvent"
@blur="blurEvent"
@focus="focusEvent"
@keyup="keyupEvent"
></inputable>
</template>
<script>
/*
event: cinput cblur cfocus cconfirm
*/
class Textarea implements TextareaInterface {
props = {
rows: {
type: Number,
default: 2
},
value: {
type: String,
default: ''
},
//placerholder
placeholder: {
type: String,
default: ''
},
//是否禁用输入
disabled: {
type: Boolean,
default: false
},
//控制是否聚焦
focus: {
type: Boolean,
default: false
},
//最大长度
maxlength: {
type: Number,
default: 140
},
//右下角返回键类型
returnKeyType: { //枚举值 done search next go
type: String,
default: 'done'
},
placerHolderColor: {
type: String,
default: '#bebebe'
},
cStyle: {
type: String,
default: ''
}
}
data = {
defaultStyle: "font-size: 18px; height: 75px; line-height: 25px; padding-left:10px; padding-right:10px; color: #000; text-align: left; background-color: #fff; border: 1px solid #999; border-radius: 4px;"
}
// watch = {
// value: function (val) {
// this.$refs['c-textarea'].value = val
// }
// }
computed ={
computedStyle() {
return this.defaultStyle + this.cStyle
}
}
methods = {
inputEvent(e) {
this.$cmlEmit('input', {
value: e.target.value || ''
});
this.$cmlEmit('inputevent', {
value: e.target.value || ''
});
},
blurEvent(e) {
window.scroll(0,0); // 键盘收起留白的bug
this.$cmlEmit('blur');
this.$cmlEmit('blurevent');
},
focusEvent(e) {
this.$cmlEmit('focus');
this.$cmlEmit('focusevent');
},
// support enter key event
keyupEvent (e) {
this.$cmlEmit('confirm')
this.$cmlEmit('confirmevent')
}
}
// mounted() {
// this.changeFocus(this.focus);
// // textarea无法默认赋值
// this.$refs['c-textarea'].value = this.value;
// }
}
export default new Textarea();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"web": {
"component": true,
"usingComponents": {
"inputable": "../../assets/vue/inputable"
}
}
}
</script>
<template>
<textarea
value="{{value}}"
placeholder="{{placeholder}}"
disabled="{{disabled}}"
maxlength="{{maxlength}}"
rows="{{rows}}"
c-bind:input="inputEvent"
c-bind:blur="blurEvent"
c-bind:focus="focusEvent"
c-bind:confirm="confirmEvent"
ref="weextextarea"
return-key-type="{{returnKeyType}}"
style="{{computedStyle}}"
></textarea>
</template>
<script>
/*
event: cinput cblur cfocus cconfirm
*/
class Textarea implements TextareaInterface {
props = {
//textarea的内容
value: {
type: String,
default: ''
},
//textarea的placerholder
placeholder: {
type: String,
default: ''
},
//是否禁用textarea输入
disabled: {
type: Boolean,
default: false
},
//控制textarea是否聚焦
focus: {
type: Boolean,
default: false
},
//最大长度
maxlength: {
type: Number,
default: 140
},
//右下角返回键类型
returnKeyType: { //枚举值 done search next go
type: String,
default: 'done'
},
placerHolderColor: {
type: String,
default: '#666'
},
cStyle: {
type: String,
default: ''
},
rows: {
type: Number,
default: 2
}
}
data = {
defaultStyle: "font-size: 40cpx; height: 150cpx; line-height: 50cpx; padding-left:20cpx; padding-right:20cpx; color: #000; text-align: left; background-color: #fff; border: 1px solid #999; border-radius: 8cpx;"
}
computed ={
computedStyle() {
let style = this.defaultStyle + this.cStyle;
if(style[style.length-1] !== ';') {
style +=';'
}
style += `placeholder-color: ${this.placerHolderColor};`
return style;
}
}
watch = {
focus: function(newVal, oldVal) {
// this.changeFocus(newVal);
}
}
methods = {
changeFocus(focus) {
if(focus) {
this.$refs['weextextarea'] && this.$refs['weextextarea'].focus();
} else {
this.$refs['weextextarea'] && this.$refs['weextextarea'].blur();
}
},
inputEvent(e) {
this.$cmlEmit('input',{
value: e.detail.value || ''
})
this.$cmlEmit('inputevent',{
value: e.detail.value || ''
})
},
blurEvent(e) {
this.$cmlEmit('blur')
this.$cmlEmit('blurevent')
},
focusEvent(e) {
this.$cmlEmit('focus')
this.$cmlEmit('focusevent')
},
confirmEvent(e) {
this.$cmlEmit('confirm')
this.$cmlEmit('confirmevent')
}
}
mounted() {
// this.changeFocus(this.focus);
}
}
export default new Textarea();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"weex": {
"component": true
}
}
</script>
\ No newline at end of file
<template>
<textarea
value="{{value}}"
placeholder="{{placeholder}}"
disabled="{{disabled}}"
maxlength="{{maxlength}}"
style="{{wxStyle}}"
c-bind:input="inputEvent"
c-bind:blur="blurEvent"
c-bind:focus="focusEvent"
c-bind:confirm="confirmEvent"
focus="{{focus}}"
confirm-type="{{returnKeyType}}"
placeholder-style="{{wxPlaceHolderStyle}}"
>
</textarea>
</template>
<script>
/*
event: cinput cblur cfocus cconfirm
*/
class Textarea implements TextareaInterface {
props = {
//textarea的内容
value: {
type: String,
default: ''
},
//textarea的placerholder
placeholder: {
type: String,
default: ''
},
//是否禁用textarea输入
disabled: {
type: Boolean,
default: false
},
//控制textarea是否聚焦
focus: {
type: Boolean,
default: false
},
//最大长度
maxlength: {
type: Number,
default: 140
},
//右下角返回键类型
returnKeyType: { //枚举值 done search next go
type: String,
default: 'done'
},
placerHolderColor: {
type: String,
default: '#666'
},
cStyle: {
type: String,
default: ''
},
rows: {
type: Number,
default: 2
}
}
data = {
defaultStyle: "font-size: 40cpx; height: 150cpx; line-height: 50cpx; padding-left:20cpx; padding-right:20cpx; color: #000; text-align: left; background-color: #fff; width:auto; border: 1px solid #999; border-radius: 8cpx;"
}
computed ={
wxPlaceHolderStyle() {
return `color: ${this.placerHolderColor}`
},
wxStyle() {
let style = this.defaultStyle + this.cStyle;
return style;
}
}
watch = {
focus: function(newVal, oldVal) {
}
}
methods = {
inputEvent(e) {
this.$cmlEmit('input',{
value: e.detail.value || ''
})
this.$cmlEmit('inputevent',{
value: e.detail.value || ''
})
},
blurEvent(e) {
this.$cmlEmit('blur')
this.$cmlEmit('blurevent')
},
focusEvent(e) {
this.$cmlEmit('focus')
this.$cmlEmit('focusevent')
},
confirmEvent(e) {
this.$cmlEmit('confirm')
this.$cmlEmit('confirmevent')
}
}
}
export default new Textarea();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"wx": {
"component": true
}
}
</script>
\ No newline at end of file
<script cml-type="interface">
//定义事件detail对象的参数
type EventDetail = {
}
interface VideoInterface {
controls: Boolean,
autoplay: Boolean,
loop: Boolean,
src: String,
customstart(eventDetail: void): void;
custompause(eventDetail: void): void;
customfinish(eventDetail: void): void;
customfail(eventDetail: void): void;
start(eventDetail: void): void;
pause(eventDetail: void): void;
finish(eventDetail: void): void;
fail(eventDetail: void): void;
}
</script>
<template>
<videoable
:controls="controls"
:autoplay="autoplay"
:loop="loop"
:src="src"
@start="onstart"
@pause="onpause"
@finish="onfinish"
@fail="onfail"
></videoable>
</template>
<script>
class Video implements VideoInterface {
props = {
controls: {
type: Boolean,
default: false
},
autoplay: {
type: Boolean,
default: false
},
loop: {
type: Boolean,
default: false
},
src: {
type: String,
default: ''
}
}
methods = {
onstart (e) {
this.$cmlEmit('start')
this.$cmlEmit('customstart')
},
onpause (e) {
this.$cmlEmit('pause')
this.$cmlEmit('custompause')
},
onfinish (e) {
this.$cmlEmit('finish')
this.$cmlEmit('customfinish')
},
onfail (e) {
this.$cmlEmit('fail')
this.$cmlEmit('customfail')
}
}
}
export default new Video();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"base": {
"usingComponents": {
"videoable": "../../assets/vue/videoable"
}
},
"web": {
"component": true
}
}
</script>
<template>
<video
controls="{{controls}}"
autoplay="{{autoplay}}"
loop="{{loop}}"
src="{{src}}"
c-bind:start="onstart"
c-bind:pause="onpause"
c-bind:finish="onfinish"
c-bind:fail="onfail"
>
</video>
</template>
<script>
class Video implements VideoInterface {
props = {
controls: {
type: Boolean,
default: false
},
autoplay: {
type: Boolean,
default: false
},
loop: {
type: Boolean,
default: false
},
src: {
type: String,
default: ''
}
}
methods = {
onstart (e) {
this.$cmlEmit('start')
this.$cmlEmit('customstart')
},
onpause (e) {
this.$cmlEmit('pause')
this.$cmlEmit('custompause')
},
onfinish (e) {
this.$cmlEmit('finish')
this.$cmlEmit('customfinish')
},
onfail (e) {
this.$cmlEmit('fail')
this.$cmlEmit('customfail')
}
}
}
export default new Video();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"weex": {
"component": true
}
}
</script>
<template>
<video
controls="{{controls}}"
autoplay="{{autoplay}}"
loop="{{loop}}"
src="{{src}}"
c-bind:play="onstart"
c-bind:pause="onpause"
c-bind:ended="onfinish"
c-bind:error="onfail"
>
</video>
</template>
<script>
class Video implements VideoInterface {
props = {
controls: {
type: Boolean,
default: false
},
autoplay: {
type: Boolean,
default: false
},
loop: {
type: Boolean,
default: false
},
src: {
type: String,
default: ''
}
}
methods = {
onstart (e) {
this.$cmlEmit('start')
this.$cmlEmit('customstart')
},
onpause (e) {
this.$cmlEmit('pause')
this.$cmlEmit('custompause')
},
onfinish (e) {
this.$cmlEmit('finish')
this.$cmlEmit('customfinish')
},
onfail (e) {
this.$cmlEmit('fail')
this.$cmlEmit('customfail')
}
}
}
export default new Video();
</script>
<style scoped>
</style>
<script cml-type="json">
{
"wx": {
"component": true
}
}
</script>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册