8.7 发布—WinterCG 合规性第 1 部分
了解更多

NativeScript 中的属性系统允许将原生平台属性暴露给 JavaScript 组件,并提供了一些内置的保证;例如

  • 它只会在原生平台对象创建后才设置属性
  • 它允许使用自定义值转换器定义属性
  • 它会自动检测属性值是否更改
  • 它可以根据需要暂停更新值
  • 它可以根据需要在属性更改时自动请求布局更新

在 NativeScript 中,Property 类充当基本属性系统,是对 Object.defineProperty 函数的简单增强。此类还包含补充回调,例如 valueChange、valueConverter 和 equalityComparer。

使用属性

向 View 实例添加新属性

通过创建具有所需 选项 的新 Property 来添加新属性。

ts
class MyButtonBase extends Button {}
export const textProperty = new Property<MyButtonBase, string>({
  name: 'text',
  defaultValue: '',
  affectsLayout: true,
})

然后使用所需的类注册属性

ts
textProperty.register(MyButtonBase)

要将 JS 值应用于暴露的原生视图,请在属性实例上调用 setNative 方法。

ts
[textProperty.setNative](value: string) {
    this.nativeView.text = value
}

要全面了解 NativeScript 如何使用属性系统来暴露原生 UI 组件,建议阅读名为 如何创建使用原生 iOS 和 Android 视图的 NativeScript 插件(第 1 部分)- 标签跑马灯! 的文章。本文提供了一个实用的现实世界示例,演示了开发 NativeScript 插件并使用原生 iOS 和 Android 视图的过程。

添加新 CSS 属性

要添加新 CSS 属性,请使用 CssProperty 类。它扩展了 Property 类,以接受额外的 cssName 选项。CSS 属性使用 Style 类注册。

ts
import { CssProperty, Style } from '@nativescript-core'

export const myOpacityProperty = new CssProperty<Style, number>({
  name: 'myOpacity',
  cssName: 'my-opacity',
  defaultValue: 1,
  valueConverter: (v) => {
    const x = parseFloat(v)
    if (x < 0 || x > 1) {
      throw new Error(`opacity accepts values in the range [0, 1]. Value: ${v}`)
    }

    return x
  },
})
myOpacityProperty.register(Style)

随后,任何 Style 类实例都将具有 myOpacity 属性,开发人员可以在 CSS 中按如下方式设置它

css
.some-class {
  my-opacity: 0.5;
}

可继承属性

要创建可应用于视图并由该视图的子视图继承的 CSS 属性,请实例化 InheritedCssProperty 类,并向其传递 PropertyOptions 对象。然后使用 setInheritedValue: (value: U) 方法设置继承值。可继承属性的示例包括FontSizeFontWeightColor 等。

ts
import { Color, InheritedCssProperty, Style } from '@nativescript-core'

export const selectedBackgroundColorProperty = new InheritedCssProperty<
  Style,
  Color
>({
  name: 'selectedBackgroundColor',
  cssName: 'selected-background-color',
  equalityComparer: Color.equals,
  valueConverter: (v) => new Color(v),
})
selectedBackgroundColorProperty.register(Style)

简写属性

要创建可以使用简写语法规则应用的 CSS 属性,请使用 ShorthandProperty 类,并向其传递 ShorthandPropertyOptions 对象。例如,您无需使用单独的规则为每边设置边距,

css
.title {
  margin-top: 0;
  margin-right: 10;
  margin-bottom: 0;
  margin-left: 10;
}

可以使用一条规则来设置所有边的边距。

css
.title {
  margin: 0 10 0 10;
}

要创建简写属性,请使用 CssProperty 类以通常的方式单独定义所有属性。然后使用 ShorthandProperty 类的 getter() 方法返回简写。以下是如何实现边距简写的示例

ts
const marginProperty = new ShorthandProperty<
  Style,
  string | CoreTypes.PercentLengthType
>({
  name: 'margin',
  cssName: 'margin',
  getter: function (this: Style) {
    if (
      PercentLength.equals(this.marginTop, this.marginRight) &&
      PercentLength.equals(this.marginTop, this.marginBottom) &&
      PercentLength.equals(this.marginTop, this.marginLeft)
    ) {
      return this.marginTop
    }

    return `${PercentLength.convertToString(
      this.marginTop
    )} ${PercentLength.convertToString(
      this.marginRight
    )} ${PercentLength.convertToString(
      this.marginBottom
    )} ${PercentLength.convertToString(this.marginLeft)}`
  },
  converter: convertToMargins,
})
marginProperty.register(Style)

创建可强制转换属性

要创建可强制转换属性,请使用 CoercibleProperty 类,并向其传递 CoerciblePropertyOptions 对象。

ts
export const selectedIndexProperty = new CoercibleProperty<
  SegmentedBar,
  number
>({
  name: 'selectedIndex',
  defaultValue: -1,
  valueChanged: (target, oldValue, newValue) => {
    target.notify(<SelectedIndexChangedEventData>{
      eventName: SegmentedBar.selectedIndexChangedEvent,
      object: target,
      oldIndex: oldValue,
      newIndex: newValue,
    })
  },

  // in this case the coerce value will change depending on whether the actual number of items
  // is more or less than the value we want to apply for selectedIndex
  coerceValue: (target, value) => {
    let items = target.items
    if (items) {
      let max = items.length - 1
      if (value < 0) {
        value = 0
      }
      if (value > max) {
        value = max
      }
    } else {
      value = -1
    }

    return value
  },

  valueConverter: (v) => parseInt(v),
})
selectedIndexProperty.register(SegmentedBar)

随后,在为属性赋值时,请调用 coerce() 方法。

ts
[itemsProperty.setNative](value: SegmentedBarItem[]) {
 ...
    selectedIndexProperty.coerce(this);
}

属性系统参考

Property 类

Property 类具有以下成员。

constructor

ts
property = new Property<MyClass, U>(propertyOptions)

enumerable

ts
isEnumerable: boolean = property.enumerable

configurable

ts
isConfigurable: boolean = property.configurable

writable

ts
isWritable: boolean = property.writable

name

ts
propertyName: string = property.name

getDefault

ts
;[property.getDefault]()

setNative

ts
[property.setNative](value){

}

defaultValue

ts
defaultValue: U = property.defaultValue

nativeValueChange

ts
property.nativeValueChange(owner: T, value: U)

isStyleProperty

ts
isStyleProperty: boolean = property.isStyleProperty

get()

ts
propertyValue: U = property.get()

set()

ts
property.set(value: U)

register()

ts
property.register(SomeClass)

isSet()

ts
isPropertySet: boolean = property.isSet(instance: T)

### overrideHandlers()

ts
property.overrideHandlers(options: PropertyOptions<T, U>)

PropertyOptions 接口

name

ts
{
  name: 'propertyName'
}

defaultValue

ts
{
  defaultValue: someValue
}

affectsLayout

ts
{
  affectLayout: true
}

equalityComparer

ts
{
  equalityComparer: (x, y) => {
    // compare x to y and return boolean
    return true
  }
}

valueChanged

ts
{
  valueChanged: (target: T, oldValue: U, newValue: U) => {}
}

valueConverter

ts
{
  valueConverter: (value: string) => {
    return someValue
  }
}

CssPropertyOptions 接口

cssName

ts
{
  cssName: 'my-css-property'
}

打算在 CSS 规则中使用的属性名称。

ShorthandPropertyOptions 接口

ts
{
  name: 'newProperty'
}

cssName

ts
{
  cssName: 'my-css-property'
}

converter()

ts
{
}

getter()

ts
{
    getter: function (this: Style){
        return cssValue
    }
}
下一个
样式