flutter_vue2 0.1.0
flutter_vue2: ^0.1.0 copied to clipboard
A Flutter library that provides Vue2-like syntax for reactive component development with type safety and complex object support.
Flutter Vue2 #
A Flutter library that provides Vue2-like syntax for reactive component development.
Features #
- 🎯 Data: Reactive data management, similar to Vue2's data option
- 🔧 Methods: Method management, similar to Vue2's methods option
- 📦 Props: Property passing and validation, similar to Vue2's props option
- 🔄 Reactive: Automatic UI updates when data changes
- 🎨 Flexible: Support for both inheritance and functional component creation
- 🛡️ Type Safe: Complete generic support and type checking
- 🏗️ Complex Types: Support for custom objects, deep nesting and reactive objects
- ⚡ High Performance: Smart change detection and optimized update mechanism
Installation #
Add dependency in pubspec.yaml:
dependencies:
flutter_vue2:
path: ../flutter_vue2 # or install from pub.dev
Quick Start #
Method 1: Inherit VueComponent #
import 'package:flutter_vue2/flutter_vue2.dart';
class CounterComponent extends VueComponent {
@override
Map<String, dynamic> data() {
return {
'count': 0,
'message': 'Click button to increment count',
};
}
@override
Map<String, Function> methods() {
return {
'increment': (MethodContext ctx) {
final currentCount = ctx.getData<int>('count');
ctx.setData('count', currentCount + 1);
ctx.setData('message', 'Current count: ${currentCount + 1}');
},
};
}
@override
Widget build(BuildContext context, VueComponentInstance instance) {
return Column(
children: [
Text(instance.data.get<String>('message')),
Text('${instance.data.get<int>('count')}'),
ElevatedButton(
onPressed: () => instance.methods.call('increment'),
child: Text('+'),
),
],
);
}
}
Method 2: Use Vue.component #
Vue.component(
initialData: {
'count': 0,
},
methods: {
'increment': (MethodContext ctx) {
final count = ctx.getData<int>('count');
ctx.setData('count', count + 1);
},
},
builder: (instance) {
return Column(
children: [
Text('${instance.data.get<int>('count')}'),
ElevatedButton(
onPressed: () => instance.methods.call('increment'),
child: Text('+'),
),
],
);
},
)
Core Concepts #
Data #
Data manages the reactive state of components, similar to Vue2's data option:
@override
Map<String, dynamic> data() {
return {
'count': 0,
'message': 'Hello Vue2',
'items': <String>[],
'user': {
'name': 'John',
'age': 25,
},
};
}
Access and modify data in methods:
// Get data
final count = ctx.getData<int>('count');
final message = ctx.getData<String>('message');
// Set single data
ctx.setData('count', count + 1);
// Set multiple data
ctx.setAllData({
'count': 10,
'message': 'Batch update',
});
Methods #
Methods define component behavior logic, similar to Vue2's methods option:
@override
Map<String, Function> methods() {
return {
// Method without parameters
'reset': (MethodContext ctx) {
ctx.setData('count', 0);
},
// Method with parameters
'updateUser': (MethodContext ctx, String name, int age) {
ctx.setAllData({
'user': {
'name': name,
'age': age,
},
});
},
// Async method
'fetchData': (MethodContext ctx) async {
// Simulate API call
await Future.delayed(Duration(seconds: 1));
ctx.setData('loading', false);
},
};
}
Call methods:
// Call without parameters
instance.methods.call('reset');
// Call with parameters
instance.methods.call('updateUser', ['Jane', 30]);
Props #
Props pass data from parent to child components, similar to Vue2's props option:
@override
Map<String, PropDefinition> propsDefinition() {
return {
// Required string property
'title': PropDefinition(
type: String,
required: true
),
// Integer property with default value
'count': PropDefinition(
type: int,
defaultValue: 0
),
// Property with validation
'email': PropDefinition(
type: String,
validator: (value) => value.contains('@'),
),
};
}
Use props in components:
@override
Widget build(BuildContext context, VueComponentInstance instance) {
final title = instance.props.get<String>('title');
final count = instance.props.get<int>('count');
return Column(
children: [
Text(title),
Text('Count: $count'),
],
);
}
Pass props:
MyComponent(
props: {
'title': 'Title',
'count': 10,
'email': 'user@example.com',
},
)
Advanced Features #
Complex Type Support #
// Custom user class
class User {
String name;
int age;
List<String> hobbies;
User({required this.name, required this.age, required this.hobbies});
User copyWith({String? name, int? age, List<String>? hobbies}) {
return User(
name: name ?? this.name,
age: age ?? this.age,
hobbies: hobbies ?? this.hobbies,
);
}
}
class UserComponent extends VueComponent {
@override
Map<String, dynamic> data() {
return {
'user': User(name: 'John', age: 25, hobbies: ['Programming', 'Reading']),
'users': <User>[],
'userMap': <String, User>{},
};
}
@override
Map<String, Function> methods() {
return {
'updateUser': (MethodContext ctx, String newName) {
final user = ctx.getData<User>('user');
ctx.setData('user', user.copyWith(name: newName));
},
'addHobby': (MethodContext ctx, String hobby) {
final user = ctx.getData<User>('user');
final newHobbies = List<String>.from(user.hobbies)..add(hobby);
ctx.setData('user', user.copyWith(hobbies: newHobbies));
},
};
}
}
Reactive Objects #
import 'package:flutter_vue2/flutter_vue2.dart';
// Use Reactive wrapper
Vue.component(
initialData: {
'counter': ReactiveFactory.ref(0),
'user': ReactiveFactory.reactiveMap({
'name': 'Jane',
'age': 30,
}),
'items': ReactiveFactory.reactiveList<String>(['Apple', 'Banana']),
},
methods: {
'increment': (MethodContext ctx) {
final counter = ctx.getData<Reactive<int>>('counter');
counter.value++; // Automatically triggers UI update
},
'updateUserName': (MethodContext ctx, String newName) {
final user = ctx.getData<Reactive<Map<String, dynamic>>>('user');
user.setProperty('name', newName); // Deep reactivity
},
'addItem': (MethodContext ctx, String item) {
final items = ctx.getData<Reactive<List<String>>>('items');
items.add(item); // List changes automatically respond
},
},
builder: (instance) {
final counter = instance.data.get<Reactive<int>>('counter');
final user = instance.data.get<Reactive<Map<String, dynamic>>>('user');
return Column(
children: [
Text('Count: ${counter.value}'),
Text('User: ${user.getProperty<String>('name')}'),
// ... other UI
],
);
},
)
Type-Safe Data Access #
// Type-safe access
final userName = instance.data.get<String>('userName');
final userAge = instance.data.get<int>('userAge');
final userList = instance.data.get<List<User>>('users');
// Safe access (returns null if not exists or type mismatch)
final userName = instance.data.getSafe<String>('userName');
// Access with default value
final userName = instance.data.getOrDefault<String>('userName', 'Default User');
// Deep object property access
instance.data.updateProperty<String>('user', 'name', 'New Name');
final userName = instance.data.getProperty<String>('user', 'name');
API Reference #
VueData #
get<T>(String key): Get data (type safe)getSafe<T>(String key): Safe get datagetOrDefault<T>(String key, T defaultValue): Get data or default valueset<T>(String key, T value): Set data (type safe)setAll(Map<String, dynamic> data): Set multiple dataupdateProperty<T>(String key, String property, T value): Update object propertygetProperty<T>(String key, String property): Get object propertyhas(String key): Check if key existsgetType(String key): Get key typeremove(String key): Remove dataclear(): Clear all data
VueMethods #
call<T>(String name, [List<dynamic>? args]): Call methodhas(String name): Check if method existsregister(String name, Function method): Register method
VueProps #
get<T>(String name): Get prop valuehas(String name): Check if prop existsdefine(String name, {...}): Define prop
MethodContext #
Method execution context, provides access to data:
getData<T>(String key): Get data value (type safe)getDataSafe<T>(String key): Safe get data valuegetDataOrDefault<T>(String key, T defaultValue): Get data value or defaultsetData<T>(String key, T value): Set data value (type safe)setAllData(Map<String, dynamic> data): Set multiple dataupdateProperty<T>(String key, String property, T value): Update object propertygetProperty<T>(String key, String property): Get object property
Complete Examples #
Check the following example files:
example/main.dart- Basic usage examplesexample/complex_types_example.dart- Complex types and reactive objects examples
License #
MIT License